Check for SSL certificate expiration of Radmind client certificates

You can find out if an SSL certificate has expired with the command below. I’ve found it useful to be able to check for expired certificates in my use of Radmind, where you can uniquely identify clients to the server with them.

$ openssl x509 -in /path/to/cert.pem -noout -checkend 0

I mention this command primarily because I reviewed the the OpenSSL x509 man page (“man x509”) that comes with Mac OS X Leopard, and it didn’t show the “checkend” option for the command. That was odd, because that option was just what I needed.

I did, however, find it documented in the usage statement-style help for the command:

$ openssl x509 --help

In that usage statement, the “checkend” option is described (with little punctuation) as a way to “check whether the cert expires in the next arg seconds [sic] exit 1 if so, 0 if not.” So, using zero seconds shows you if the certificate has already expired, while an integer greater than zero will show if it will expire in the future. No matter how many seconds you check against, you must examine the results from the exit code (the “$?” shell variable) to see if the certificate is or has expired.

I find this is tremendously useful knowledge when dealing with certificates in Radmind, where an expired certificate can mean the failure of a client to connect to the Radmind server. It could be beneficial in other circumstances, of course — but I don't have those circumstances.

Taking this further, you could check for certificate expiration on a Radmind server — if your certificates are stored in the Radmind special directory for each hostname of a managed client. (Substitute one of your own managed clients’ hostnames for “hostname” in the path below.)

$ openssl x509 -in /var/radmind/special/hostname/private/var/radmind/cert/cert.pem -noout -checkend 0

Since you can do it for one client certificate, you could also loop through all of the certificates on a Radmind server. In this example, I’ll continue to use the path of /var/radmind even though, on Mac OS X, I’d generally prefer to specify the full /private/var/radmind; your Radmind server may not be on Mac OS X even if your clients are. Also, you may need to modify the “depth” parameter on your search to accommodate the paths on your server. Finally, I’ll change the “checkend” parameter to 604800, for seven days (606024*7=604800). That produces something along the lines of:

for CERT_PATH in <code>find /var/radmind/special -name cert.pem -print -type f -depth 6</code>;
    CERT_HOST=<code>echo ${CERT_PATH} | cut -f 5 -d &#039;/&#039;</code>
    openssl x509 -in ${CERT_PATH} -noout -checkend 604800
    case ${RESULT} in
          echo "${CERT_HOST}: okay"
          echo "${CERT_HOST}: expiring"

Change the last line to “done | grep expiring” if you only want to see the expiring certificates.

for CERT_PATH in <code>find /var/radmind/special -name cert.pem -print -type f -depth 6</code>;
    CERT_HOST=<code>echo ${CERT_PATH} | cut -f 5 -d &#039;/&#039;</code>
    openssl x509 -in ${CERT_PATH} -noout -checkend 604800
    case ${RESULT} in
          echo "${CERT_HOST}: okay"
          echo "${CERT_HOST}: expiring"
done | grep expiring

It’s great to get just the CN of the certificate in these circumstances, since it’s likely you’ll want to act on just those that need attention. One way to do this relatively cleanly is to use OpenSSL x509’s “subject” and “nameopt” options, and then parse the output. Below, I’ll use awk for that. (Again, substitute one of your own managed clients’ hostnames for “hostname” in the path below.)

$ openssl x509 -in /private/var/radmind/special/hostname/private/var/radmind/cert/cert.pem -noout -subject -nameopt sep_multiline | awk '/CN/ {split($1,elements,"=") ; print elements[2] ;}'

To get the CNs of only those certificates needing attention:

for CERT_PATH in <code>find /var/radmind/special -name cert.pem -print -type f -depth 6</code>;
    openssl x509 -in ${CERT_PATH} -noout -checkend 604800
    case ${RESULT} in
            openssl x509 -in ${CERT_PATH} -noout -subject -nameopt sep_multiline | awk '/CN/ {split($1,elements,"=") ; print elements[2] ;}'

Getting even fancier, you can find out just which certificate CNs are expiring or expired compared to the managed hosts listed in your config file. (Make sure you don’t get any that are commented out, and also watch out for curly braces.) You can accomplish much of that with this snippet:

for CERT_PATH in <code>find /var/radmind/special -name cert.pem -print -type f -depth 6</code>;
    openssl x509 -in ${CERT_PATH} -noout -checkend 604800
    case ${EXPIRE_RESULT} in
            openssl x509 -in ${CERT_PATH} -noout -checkend 0
            case ${EXPIRED_RESULT} in
            CERT_CN=<code>openssl x509 -in ${CERT_PATH} -noout -subject -nameopt sep_multiline | awk &#039;/CN/ {split($1,elements,&quot;=&quot;) ; print elements[2] ;}&#039;</code>
            grep -E '^{?[A-Za-z0-9.,]</em>'${CERT_CN}'.' --quiet /var/radmind/config
            case ${GREP_RESULT} in
                    echo "${CERT_CN}: ${EXPIRE_DEGREE}, found uncommented in config file"

Beyond checking for expiration on the server, it may be valuable to do so in your Radmind client scripts, especially if you favor SSL connections. If you find an expired certificate, you can take some remedial action right away that might allow the client to communicate with the server.

I thought about this a while, and the easiest way I came up with — after having already developed more complex logic — was to simply rename or remove the expired certificate from its normal path. Then, allow the client to connect with another authorization level where the client certificate is unnecessary. (Use of a client certificate implies Ramind’s “-w2” authorization level, while a lesser level would mean you’re performing hostname/DNS rather than certificate verification.) This would probably mean you have multiple Radmind server processes running, each on its own port, to accept such incoming requests on the server.

An Epic Introduction to PyObjC and Cocoa

Irrational Exuberance has An Epic Introduction to PyObjC and Cocoa. Skimming over it, it really does seem to start at the ground level — and that’s what I need. I have high hopes it will help me figure out PyObjC.

[Via PyObjC Development mailing list.]

List changed files in a Mercurial repository with a custom output style

While trying to troubleshoot what I’d done to mess up the Mercurial repositories managing my Drupal installations last weekend, I really would have liked a way to see what files had changes in specific revisions. Each revision to a Mercurial repository affects some files, of course, but it seems awfully hard to figure what files changed in that check-in.

I have since found a way to do that by customizing the output of Mercurial. To customize output, you can create templates on the command line (with --template) or for more powerful reformatting, create an output style file.

I struggled for a while to figure out how to use style files, and eventually came up with something that works for me so far.

Since I’ve installed Mercurial from Lee Cantey’s standard binary package for Mac OS X Leopard, I created the file “map-cmdline.changedfiles” at the “/Library/Python/2.5/site-packages/mercurial/templates” path. (Where you put the file may vary depending on where Mercurial is installed, and I’m sorry but I don’t know where it gets installed on other systems.) The contents of “map-cmdline.changedfiles” are below, along with my possibly inept description of what each line is doing:

# Get all of the files in the selected revision

and stringify them, whatever that means

but do not 'tabindent' or wrap them to 68/76 columns

Without first setting changeset to the list of files

you won't get output from subsequent lines

changeset = '{files|stringify}'

List modified files, one per line

preceded by M to mimic hg status

file = 'M {file}\n'
last_file = 'M {file}\n'

List added files, one per line

preceded by A to mimic hg status

file_add = 'A {file_add}\n'
last_file_add = 'A {file_add}\n'

List deleted files, one per line

preceded by ! to mimic hg status

file_del = '! {file_del}\n'
last_file_del = '! {file_del}\n'

I don’t know why the “map-cmdline.” portion of the filename is there, but as long as I have it, I can call the style file from the command line with what follows the period. So, I can call the style with “--style changedfiles” — and that tiny bit of voodoo seems reasonable enough to me. (The other styles in the directory above, many of which end in “.tmpl” extensions, seem related to the Mercurial Web server, hgweb. I tried, but I couldn’t use their names at the command line, with or without their extensions. Plus, their contents looked HTML-ish.)

With the “map-cmdline.changedfiles” style file saved in that location, I can call Mercurial’s “log” command:

$ hg log --style changedfiles -r tip

… which gives me a list of the files changed in the “tip” (or latest revision) of the repository. I could substitute in any revision identifier for “tip.”

I haven’t actually seen the “file_add” and “file_del” keywords in action; every time I’ve used this style file in the manner described, I’ve only seen files marked as “M” — even if I’m looking at a revision where new files were first checked into the repo. I’m confused by that, but I’m not going to let it sour my day at this point.

There might have been an easier way to do this but I didn’t find one last weekend. It took me some time to figure even this bit out, and I hope writing this post saves someone new to Mercurial from future frustration.

Launch Services database manipulation with lsregister

While you could clear the various LaunchServices databases by deleting files, I prefer to use a more targeted command line tool when possible. My assumption is that the command line tool is canonical and will therefore produce more reliable results.

In Mac OS X Tiger, you could clear the LaunchServices database using the following “lsregister” command:

$ /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LaunchServices.framework/
Versions/Current/Support/lsregister -kill -r -domain system -domain local -domain user

But, in Leopard, the LaunchServices framework’s path has moved; it is now in the CoreServices framework bundle. You can find it with the “find” command:

$ find /System -name lsregister -type f -print 2>/dev/null

Once you find it, you can get the usage statement for the “lsregister” command in Leopard, which will at least tell you what options it has:

$ /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/

lsregister: [OPTIONS] [ ... ]
[ -apps [,domain]... ]
[ -libs [,domain]... ]
[ -all [,domain]... ]
Paths are searched for applications to register with the Launch Service database.
Valid domains are "system", "local", "network" and "user". Domains can also
be specified using only the first letter.
-kill Reset the Launch Services database before doing anything else
-seed If database isn't seeded, scan default locations for applications and libraries to register
-lint Print information about plist errors while registering bundles
-convert Register apps found in older LS database files
-lazy n Sleep for n seconds before registering/scanning
-r Recursive directory scan, do not recurse into packages or invisible directories
-R Recursive directory scan, descending into packages and invisible directories
-f force-update registration even if mod date is unchanged
-u unregister instead of register
-v Display progress information
-dump Display full database contents after registration
-h Display this help

Note that if you’re having Launch Services-related problems in one user account but not another, you’ll likely want to start with the “user” domain. (It pays to understand the domain structure of Mac OS X, so that you only make changes where you need to.)

Untar archive contents directly into a target folder

In my Mercurial-based workflow for updating Drupal sites, there is a sequence of commands I need whenever a new version of Drupal comes out. I have a hard time remembering the options for “tar” in this sequence — and my original source for the instructions differs from what I need to do on my Web host — so I need to help my memory. The tar command, as constructed below, places its output into the specified destination directory.

Here it is, with tar’s “--strip-path=1” and “-C” options:

$ cd path/to/repository/parent/directory
$ curl -O
$ tar --strip-path=1 -C drupal_source -zxv -f drupal-5.12.tar.gz

Find Info.plist files for applications on Mac OS X

There is some important information in the Info.plist files contained in Mac OS X applications. But, some of that information isn’t really standardized — I’m looking at all of you, you crazy version number and vendor attributes (just the ones I'm interested in!). So, given that, how do you find them all to make comparisons between Apple and third-party apps?

Answer: You can use the “find” command to find all of the Info.plist files for applications in your /Applications directory.

$ find /Applications -name Info.plist -ipath /Applications/*.app/Contents/Info.plist -depth 3 -print 2>/dev/null

Since that intentionally limits the depth traversal, you could modify it slightly to support finding Info.plists in your /Applications/Utilities directory, as well. However, I would say it’s less likely you’ll be dropping third-party applications in the Utilities directory, so you might not care.

Addressless Kerberos tickets in Mac OS X

I was concerned when reading Kerberos: The Definitive Guide that Mac OS X clients bound to an Active Directory didn’t have an easy way to specify that their Kerberos tickets should work behind NAT. The option to obtain addressless tickets is defined in the krb5.conf file (or, for Mac OS X, the file) with:

noaddresses = true

… And it is not an option you can choose either in the Directory Utility GUI or the dsconfigad command line tool. This is important because addressless tickets don’t have IP addresses associated with them, and thus work in situations such as those where a client is behind NAT.

Before I submitted a feature request, though, I looked up the option in the krb5.conf man page on a Leopard system. I’m glad I did, because it says:

Setting this flag causes the initial Kerberos ticket to be addressless. The default for the flag is true.

Presumably, this documented default is applying on Leopard with Active Directory Kerberos. When I examined a TGT issued by a domain, I did not see any IP addresses associated with it, so the default does appear to be the case for me.

Use an unorthodox recurrence pattern to link two related events in Microsoft Entourage

I am happy about a solution I just came up with to the problem of not being able to define an arbitrary set of dates as the recurrence pattern for an event in Microsoft Entourage 2008.

I wanted to enter an event that was split across two days, and wouldn’t have obviously fit any type of “every Wednesday” or “every second Thursday” pattern. The ideal way to handle this, I think, was available in the Steltor CorporateTime calendar I used to use: create an event and add arbitrary dates to it, so that each recurrence appeared as part of the series. You can’t do that in Entourage — or I’ve never found any trickery to allow it.

Luckily, however, the event’s start time and duration was the same on each of the two days, so I realized I didn’t need to make two different events for it. And, I only had two recurrences to deal with — if there’d been more, it’s unlikely they would have been evenly spaced.

I used my “Compare dates” AppleScript to determine how many days apart the two instances of this particular event were. I came up with 20. I entered that as the number of days between recurrences. I set the recurrence to end on the date after the last event.


The result? I got two events (and two events only), both on the days I intended, and they were linked as part of a recurrence pattern. Sweet. It’s the little victories, you know?

The Life Balance upgrade question

“Life Balance 3.x customers with Macintosh licenses can upgrade to version 4 for just $59.95,” claims Llamagraphics, the purveyor of the fine time management application, Life Balance.

This sounds like a great deal! Until I remember that the only reason I want to upgrade from version 3 to 5 (not 4) is for compatibility with the new iPhone version of Life Balance! So to get them both, I’d be spending:

Upgrade cost
Life Balance Mac upgrade $59.95
Life+Balance+for+iPhone $19.99
Subtotal $79.94

Compare that to my current cost for Life Balance — which I’m not currently using because my Treo repeatedly made me want to throw it forcefully into the ground (loved the Palm, hated the defective phone!) and the desktop software looks like crap — which I’ve summarized below:

Original cost
Life Balance Mac and Palm bundle $39.95
Life Balance Mac and Palm upgrade $50.00
Subtotal $89.95
Total $169.89

That’s right, folks. After an investment to date of $89.95 in this software, I’d have to shell out another $79.94 to stay current and get the application on the mobile device I currently use. I’d be paying more for the Mac upgrade than I’ve ever paid for any single purchase or upgrade from Llamagraphics in the past!

I’m surprised I’m even thinking about this. However, Life Balance has always made the most sense of any task management application, and has always done the best job of helping me prioritize. (Of other current applications, OmniFocus doesn’t make sense to me, and Things was great for entry but felt horrid at showing me what I needed to do next.) At the cost of Life Balance, despite how it worked for me, maybe it’s simply time to try something else.

The least expensive overall, and perhaps most interesting because it supports task sharing, is to go with Remember The Milk. I’m not sure I want to use a Web or “cloud” service for this, and there’s no desktop application per se, but I’m at the point in my life where sharing to-do’s with others (and outside the work environment) is compelling. The new+Remember+The+Milk+iPhone+application may tip me in that direction.

Microsoft and the Forgotten Realms

A while back, Microsoft announced their Silverlight software. I didn’t think much of it, but now that they have announced the Azure platform, I realized that they have developed a Forgotten Realms theme in their products.

Let’s look at this, while we’re in the beginning of the trend, to see how this relates to the the SSI “gold box” Forgotten Realms games:

Product platform How it relates To this SSI FR game
Microsoft Silverlight … silver light is the color of light that gleams off silver blades Secret of the Silver Blades
Microsoft Azure … azure is the color of the bonds tattooed on the adventurers' arms … Curse of the Azure Bonds

Based on this flimsy evidence, I suspect the next major product platform from Microsoft to be related, somehow, to “radiance.” (As in Pool of Radiance, of course.)

We might also expect a future initiative centered around “darkness,” but I consider that less likely — or, it may already have happened, given the reverse chronology that seems to be at work. (See Pools of Darkness.)

Syndicate content