I found myself recently writing a script to do user account management tasks in an environment with multiple NIS, LDAP, and Active Directory directories. Along the way, I found myself in need of a way to generate a password that was reasonably secure by fitting the requirements of our password policy. The policy we have is fairly common, since it basically is what Active Directory does when the password complexity rules are turned on.

"Great," I thought to myself. "I can just use a module from CPAN!"

There turned out to be a few, so off I went to install them and give them a try. The first thing I noticed is that they all seemed to work fairly well at doing a good bit more than I really needed. The problem however was that none of them seemed to be configurable to exactly match our password complexity requirements.

"Well, crap! I guess I'll have to write my own."

So off I went to do just that. What astonished me, was just how simple it was to write something that managed it.

use strict; use warnings; use List::Util qw(shuffle); sub gen_password { my $password; my $minlength = 8; my $maxlength = 12; my $minclasses = 3; my $other = rand($maxlength-$minlength) + $minlength - $mincl +asses; my @classes = ( ['a' .. 'z'], ['A' .. 'Z'], [0 .. 9], [qw( . ! / \ - : ; " ' ? $ ^ & @ [ ] = + | < > % * ~ ) + , qw/ ( ) /, ',', '#'], ); my @required = shuffle(0 .. $#classes); my @indexes = shuffle(@required[ map { rand @required } (1 .. +$other) ], @required[0 .. ($minclasses - 1)]); foreach my $i (@indexes) { $password .= @{$classes[$i]}[rand @{$classes[$i]}]; } return $password; }

Now, I'm not saying this is ideal code. It doesn't completely suck though, and it is pretty easily extended to cover a few things I didn't bother with. About the only significant bit I couldn't add unless I were to expend a fair amount of effort would be a bit that checked the password to see if it matched a certain number of consecutive characters of the user's name or userid. (not that such a check would be difficult, just that it would require more than a simple line of code.)

But this left me faced with a new problem. How do I address the fact that my few lines of code represent something none of the other modules do? Do I try to incorporate my code into one of the existing modules and contribute a patch to the module maintainer? Do I flesh mine out into a full module and add to the number of modules out there that meet an individual's needs but don't quite cover the bases for a majority? Do I write a module that's backward compatible with the other modules but includes the solution for my own needs in the hope that I can reduce the number of modules that have multiplied out there so far?

In the end, I've opted to take the lazy way out and post a snippet here, knowing that it will like only very rarely be found by anyone that might need it, but justifying it to myself in that it is such a short snippet that anyone could have come up with it on their own if they needed it.

Does CPAN module multiplication induce apathy and denial in anyone else, or is it just me?