Wednesday, November 25, 2009

The morality of helping

Yesterday, a friend asked me, "are you a Perl expert?"

I answered in the only way possible: "eeeeh..."

It turned out that my friend did not ask for help for himself, but for someone else, who had posted a programming class question on a non-programming bulletin board.

The poor fellow was struggling with a question of parsing a two-column input to generate a certain output format, essentially also two-column, except with a slightly different layout.

On Usenet, there was - and maybe still is - a long-standing tradition of not solving people's homework for them. The reasoning behind this is that we do not learn quite as well when people solve our problems for us, as when we struggle with them ourselves.

In some cases, school questions would be met with derision, in other cases with genuinely unhelpful and false answers, and sometimes with helpful clues about how to solve the problem; where to look, tips for using stepping debuggers, which book chapter or manual page would clarify the problem, etc.

Okay, that is fair enough.

The guy had gotten only one answer, from another guy who regretted that he had not touched Perl in ages, and therefore could not help. And I thought that Perl was like learning a particularly catchy, but annoying song: you might think that you have forgotten, but then someone hums or whistles the tune, and WHAM - there it is, stuck in your head again.

So I had a look. Maybe I could provide a hint or two, you never know. I know my way around some of the less scary parts of Perl 5 City, anyway.

This guy had essentially nailed the problem semantically, but he was evidently struggling with his code, it just did not work.

I immediately saw a few major concerns:
  1. Some parts were copy-pasted from bad textbook Perl.

  2. Some parts must have come from a poor programming education.

  3. The code was overly complex and verbose.

  4. There was no error checking or debug print-outs.

  5. And it would take me more time to helpfully point out these things than write something that might be a solution myself.
The moral dilemma then was:

Should I help the guy out by tearing his code apart and pointing out all the flaws that made it thoroughly lousy code, thereby provoking a true emo-American melodrama?

Or should I just write an alternate solution, with sound error-checking, simplicity, and debug print-outs?

In this case, I thought the latter was the way to go. I put the code up anonymously somewhere, gave the link to my friend, and perhaps the fellow with the problem now has a better understanding of how simple and beautiful Perl can be.

Yeah, right. :D

Sunday, November 15, 2009

What stops me from using Perl 6, today?

Since I got hooked on the Perl community, and got a taste of Perl 6, I've been wondering about:
  1. what, exactly, is it that I could use Perl 6 for, right now?
  2. why am I not actively using Perl 6 now?

Those are easy questions, but answering is hard, so this may be a long post.

Sure, the points listed below are not exactly Perl 6 specific; I could probably have picked some other programming language, but I somehow feel more comfortable in the way that Perl 6 still is Perl.

What I could use Perl 6 for right now


I think it's fair to say that using Perl 6 today mostly means using Rakudo, and that I wouldn't use it in what we popularly call a "production setting". But many of us programmers, sysadmins, geeks and nerds have perfectly suitable hobby projects, where we won't have clients wringing our necks if there is three minutes of downtime in a month, or if we don't deliver the Speedy Gonzalez of services; we have projects that are neither computing performance constrained or stability constrained.

So that's where I could have started using Perl 6 half a year ago, and of course still can.

I know I can use Perl 6 for e.g. a fairly complex web site using Web.pm and Squerl for a SQLite backend. It will probably work just fine, for a lot of projects.

I know I can use it for lots of one-liner scripts.

I know that in some regards, Perl 6 will outperform classic Perl 5 in terms of programmer time spent. An example is the given-when control structure, which (to me) is semantically superior to if-elsif-elsif-elsif. Programmer time is important to me, I hate coding too much for menial tasks. And I'm sorry to say that Perl 5.10 doesn't do it yet for me, as I cannot rely on its presence, even for hobby projects.

And I know I can use Perl 6 to refresh some of the knowledge about programming language specifics (terminology, technique, methodology, etc.) that I've allowed to rust since I left university in 2001.

Concrete projects, in no particular order


  • web page for registration of pool billiards tournament results; it's not performance critical, and the users could check and verify the dataset themselves after input

  • conversion of historical results data in CSV format to a database; one-time job, needs manual verification no matter what programming language I use to do it

  • contributing to the Temporal.pm specification and implementation in Perl 6

  • personal web gallery generation; I positively loathe most of the online galleries, because they sooner rather than later are discovered to have HUGE, GAPING security vulnerabilities

  • blogging tool; I'm not very comfortable with blog software running on servers, either, and whatever blogging I do, it's not actual work


That's quite a lot, isn't it? It ought to have been enough to get me going in a jiffy!

Why I'm not actively using Perl 6 now


This may be a surprise to some: it's not because of a lack of matureness in the tools, a lack of confidence in the language or tools, stability issues, etc. As I tangentially mentioned above, I believe there is no technical hindrance for me to start coding on a hobby project.

I have plenty of hobby projects to choose from. They are also quite manageable in terms of eventual lines of code.

However, there is something holding me back, and that's a certain degree of perfectionism mixed with procrastination fever.

mst mentioned during the NPW hackathon this spring that perfectionism was a barrier against getting started. If you're too obsessed with getting things right at first, at wanting to avoid failure, procrastinating is too easy. Getting slightly intoxicated (yup, drinking alcohol, which of course is only a recourse for adults) is a way of reducing your own perfection anxiety. This is almost exactly what Randall Munroe's xkcd calls the Ballmer Peak:



But I don't sleep too well after drinking alcohol, and I also tend to do hobby projects in my "running breaks" during work hours, in which case alcohol intake may be a very bad idea.

In addition, my time at work is a series of interruptions, which really isn't conductive to sitting down and learning something new and complex.

When I get home from work, I'm usually so fed up with computers that I don't want to have anything to do with them.

So my spare time, whatever is left of it, usually isn't spent on programming. Note that I don't even do these projects in a programming language I already know well; they are on hold regardless of that.

All in all, there's nothing much wrong with Perl 6.

Blaming the immaturity of Rakudo would just be a silly excuse. There's something wrong with my capacity for finding the time to get down and dirty with it, that's what; I'm apparently not currently capable of saying honestly:

This is my Perl 6 hour. This hour, I'm going to do Perl 6 stuff, and this time is sacred.

Monday, November 9, 2009

What the #perl6 IRC bots do

Do you feel like a n00b on #perl6, like I do, and wonder what the different bots do?

I keep forgetting what they are, so here's a list for you and me both:


dalek
Announces commits (mainly to rakudo, nqp-rx and the Perl 6 book)

hugme
Used for hugging another user without "direct" contact:
hugme: hug masak

ilbot2
Near-realtime IRC logs with automatic link generation to irclog.perlgeek.de. The original ilbot sucked, according to moritz.

ilogger2
Another logging bot

lambdabot
Keeps track of karma ("moritz++" adds one to moritz's karma score, "frettled--" subtracts one from mine)

lisppaste3
Announces entries pasted to http://paste.lisp.org/new/perl6 (which is where we paste code and other stuff, so that we avoid spamming the channel too much, and also don't have to worry about creating our own temporary web pages)

masak
Submits rakudo bugs. Aw, okay, then, he's not a bot, just a really nice guy!

mubot
Also tracks karma, attempting to be slightly less annoying than lambdabot. mubot is clever enough to recognize that your nick may vary slightly from time to time and channel to channel. mubot is written in Perl 6!

p6eval
Perl 6 code evaluation bot. We use this for live testing of code that may be of interest to others; it chats back to the channel. perl6: my $a; will result in a test against several Perl 6 interpreters (elf, mildew, mildew-js, pugs, rakudo, sprixel), nqp: say('foo') tests nqp-rx, std: my $a will parse the expression with STD.pm.

phenny
Our secretary. Sample usage:
phenny, tell frettled I'll get back to you on that
phenny will then let me know when I become active on the channel again.

pointme
Provides links to projects tracked by proto. Example usage:
< carlin> pointme: rssbot
< pointme> carlins's rssbot is at http://github.com/carlins/rssbot
pointme is written in Perl 6!

pugs_svn
Tracks commits to the pugs repository, most of which are changes to the test suite and spec.

zaslon
Tracks blog posts from a certain group of bloggers. Zaslon is written in Perl 6!



Thanks to carlin, Juerd, jnthn and moritz for late night clarifications!

Tuesday, November 3, 2009

Checking and fixing Unix file modes

Among other tasks in my sysadmin role at a web hosting provider, I work with fallout from poorly designed PHP code - which is ubiquitous - and I use Perl 5 to perform a bunch of semi-automated tasks.

If you just want to see how I utilize the Fcntl module, look further down.

One of the many things that tend to go wrong is the assumption that PHP always runs as mod_php (blatantly disregarding php-cgi, suphp, and other per-user PHP frameworks), and therefore directories (folders) and files used by PHP "must be" prepared with chmod 777 chmod 666. The latter number is a BIG FRIGGIN' HINT, it's the number of the beast.

Whenever documentation tells you to use the number of the beast for your chmod command, that documentation is also telling you to lube up and bend over.

Unfortunately, customers and users don't necessarily see this gotcha; no matter how good the hosting provider's documentation is, they'll naturally trust the software monger's instructions.

That means that the hosting provider ought to have tools available for identifying and fixing such writable directories and files. There are many wrong ways of doing it, one is:chmod -R, since that touches ALL files, recursively, overwriting the ctime stamp. An okay way is to use find, which (in most versions) allow you to fix things up quite neatly (bash/sh compatible syntax, GNU find compatible options, $dir represents the directory to fix recursively, $user is the username whose files you want to change):
find $dir -xdev -user $uname \
\( \( -perm /og=w -exec chmod og-w {} \; \) -o \
\( -perm /g=w -exec chmod g-w {} \; \) -o \
\( -perm /o=w -exec chmod o-w {} \; \) \)
Phew, that was quite a mouthful, but it's rather nice in resource usage, and it doesn't cross filesystem boundaries (-xdev).

So why would I want to do this in Perl, you ask?

"Eeerrr. Good question, let me tell you why!"

There are many other problems to look for, which it is sensible to look for while you're at it, just to mention a few:
  • Backdoors
  • Hidden IFRAMEs
  • Malicious JavaScript
  • Malware URLs
  • Malware redirects (e.g. in .htaccess)
  • Outdated software versions
  • Root exploits
  • Spamming scripts
  • Viruses
These things belong in a program, not a teeny weeny Unix one-liner, or even a set of them.

While you're at it, you might want to create a log of what you found, and perhaps which line numbers are relevant for which files, both for pointing out where to consider fixing things, as well as having something to use for debugging your false positives.

The code


Here's how I identify the files with too liberal write permissions, utilizing the Fnctl module. The filename is stored in $_, the user's real UID in $r_uid, and I also store various file information and what kind of file we're looking at.
use Fcntl ':mode';

my %badperms;
my ($dev,$ino,$mode,$nlink,
$uid,$gid,$rdev,$size) = lstat($_);
my $g_write = $mode & S_IWGRP;
my $o_write = $mode & S_IWOTH;
my ($isfile,$isdir,$islink) = (-f _, -d _, -l _);

my $filetype = $isfile ? "File" : \
$isdir ? "Directory" : \
$islink ? "Symlink" : "Other";
my $fn = $_;

# Writable for others
if (!$islink && ($g_write || $o_write)) {
$badperms{$fn} =
sprintf ("%s: [%04o] %s\n", $filetype,
S_IMODE($mode), $fn);
}
In a future post, I'll try to get back with how this fits in my bigger picture of vulnerability detection.

As always, suggestions for improvements and questions are very welcome.