Hack Usermin to Encourage Users to Read Policy Updates!

Had an interesting situation at work recently that required a bit of hackery to make sure that everyone on the research team was on the same page. Since 95% of the actual work (everything but documentation) occurs through a central Usermin-powered portal, I had the idea to build a “nag” screen that I could periodically make users acknowledge before they’d be allowed into the system. Ideally, the system is used infrequently, only when policy changes are done that require everyone to know the new policy immediately. The system is pretty simple:

1. User Logs In, and if updates are present, they are shown the update page.

2. User reads the update, and enters a “codeword” on the update page. This is so the updates can be securely displayed (on our documentation site) while the update landing page remains static.

3. User isn’t bothered again until the next update.

The code isn’t too difficult, so I’ll post it below. Warning though: Webmin/Usermin/Virtualmin are written in PERL, and I’m a PHP sort of person, so this is a mix of both!

Step 1: Modify Usermin to Point to Landing page

The system works by having a file written to a non web-accessible server directory once the person enters the correct codeword. When I need to issue a new update, I simply delete the username-named files and everyone needs to enter a new codeword. Below is the code that you’ll have to put in Usermin’s miniserv.pl file, which on my system is located at /usr/local/usermin-1.420. You’ll also want to decide first where you want to store your “nag” files. I put them under a special directory in /var, however you can put them anywhere you’d like that the webserver can read/write to them.

The following code is inserted around line 3532, right after the post-login script statement (&run_login_script…):

#Check Nag Screen, see if we need to nag user (Added by JW on 3/2/2010)

local $nagfile = “/var/nagfiles/” . $authuser;
if (-e $nagfile) {
syslog(“info”, “%s”, “Successful Nag Check for $authuser from $acpthost”) if ($use_syslog);
}
else {
my $url = “https://landingpage_server/updates.php?user=” . $authuser;
&write_data(“HTTP/1.0 302 Moved Temporarily\r\n”);
&write_data(“Date: $datestr\r\n”);
&write_data(“Server: $config{‘server’}\r\n”);
&write_data(“Location: $url\r\n”);
&write_keep_alive(0);
&write_data(“\r\n”);
}

You’ll want to modify the URL and the nagfile location to suit your own installation. Once you save the file and reload Usermin, it will take effect.

Step 2: Create the Landing Page

I wrote a pretty simple PHP page that shows some text (using an include file) and a form, and then writes a file with the user’s username to the directory of interest. It also logs the interaction for auditing purposes. Below is my code, see the inline comments on what you need to edit/change

<?php
// Jon’s Nag Screen for Usermin. Usermin will redirect people here if Jon clears out the /var/nagfiles/ directory of username files.
// This file shows the update notice, and asks users to read and agree by entering the codeword, which is changed with each update!

// CHANGE this to whatever you want the codeword to be.
$codeword = “swimmer”;

if (isset($_POST[‘submit’])) {
// Do Form Processing

if ($_POST[‘codeword’] == $codeword)
{
// Good, right codeword, now write the login file and redirect them

// CHANGE this to the directory you’re putting the nag files into. make sure that directory is writable to Apache!

$filename = “/var/nagfiles/” . $_POST[‘user’];
$ourFileHandle = fopen($filename, ‘w’) or die(“can’t open file”);
fclose($ourFileHandle);
$ourFileHandle = fopen(‘/var/nag.log’, ‘a’) or die(“can’t open file 2”);
$logentry = “Valid Codeword Entry by ” . $_POST[‘user’] . ” at ” . date(“F j, Y, g:i a”) . “\n”;
fwrite($ourFileHandle, $logentry);
fclose($ourFileHandle);

// CHANGE this to be the location of your Usermin installtion.
header(“Location: https://xyz.com:20000”);
} else {
// Bad, wrong codeword!
$ourFileHandle = fopen(‘/var/nag.log’, ‘a’) or die(“can’t open file 2”);
$logentry = “Invalid Codeword Entry by ” . $_POST[‘user’] . ” at ” . date(“F j, Y, g:i a”) . “\n”;
fwrite($ourFileHandle, $logentry);
fclose($ourFileHandle);
print(“Wrong Codeword! Please hit the back button in your browser and try again!”);
}
}
else
{
// Show Info Screen
?>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>

<head>
<meta content=”en-us” http-equiv=”Content-Language” />
<meta content=”text/html; charset=utf-8″ http-equiv=”Content-Type” />
<title>Important Updates</title>
<style type=”text/css”>
.style1 {
text-align: center;
font-size: xx-large;
font-family: Arial, Helvetica, sans-serif;
}
.style2 {
text-align: medium;
font-size: large;
font-family: Arial, Helvetica, sans-serif;
}
.style3 {
text-align: center;
}
.style4 {
font-family: Arial, Helvetica, sans-serif;
}
.style5 {
font-family: Arial, Helvetica, sans-serif;
font-size: x-large;
}
</style>
</head>

<body>

<p>IMPORTANT!</p>
<p>New Lab Policies have recently been issued. In order
to access the Usermin, you must do the following:</p>
<p>1. Visit <A HREF=”http://update.page.com/page.html” target=_blank>This Page on the Wiki</A> detailing the changes.</p>
<p>2. Enter the codeword (provided on the page above) in the box
below and press Submit. You will then be redirected back to Usermin where you should
now be able to log in.</p>
<p><font size=2>Note: By entering the valid codeword and pressing submit, you affirm that you have read the updates, will follow the policies, and are not a zombie.</font></p>
<form method=”post”>
<div>
<span><strong>Codeword: </strong> </span><br />
<input name=”codeword” type=”text” /><input name=”user” type=”hidden” value=<?=$_GET[‘user’]; ?>><br />
<br />
<input name=”submit” type=”submit” value=”submit” /></div>
</form>

</body>

</html>

<?

}
?>

That file can be named updates.php (or whatever you want) and placed in a location that users can access.

Step 3: Create Directories, Set Permissions, Test

The last step is something you may have done already – create directories to house your files (/var/nagfiles in my example) and set the permissions to allow the Apache Webserver (and Usermin) to write to those directories.

Once the system is running, adding updates is a pretty straight forward process: Update your update page, change the codeword in updates.php, and delete all of the username-named files from /var/nagfiles. Users will now get the nag screen again after they login for the first time after updates. You may also want to periodically purge the log file, depending on how busy your usermin portal is.

While not explicitly written, this hack probably will also work with Webmin. Be sure to be careful with automatic updates to those products though – you may have to re-integrate your code into miniserv.pl after each update.

If this has been a useful document for you, please let me know, I’d love to see other people implementing creative solutions to balance ease of use and ease of policy notification!

Leave a Reply

Your email address will not be published. Required fields are marked *