Skip site navigation (1)Skip section navigation (2)
Date:      30 Dec 1999 12:04:52 -0500
From:      Chris Shenton <cshenton@uucom.com>
To:        "Brent Rector" <brentr@tccsweb.com>
Cc:        <freebsd-isp@FreeBSD.ORG>
Subject:   Re: Changing Passwords for Users using http: port 80
Message-ID:  <lf4sd04ax7.fsf@Samizdat.uucom.com>
In-Reply-To: "Troy Settle"'s message of "Wed, 29 Dec 1999 15:49:48 -0500"
References:  <FNEMIHIFMKFBMDBKFDPBGEHMCAAA.st@i-plus.net>

next in thread | previous in thread | raw e-mail | index | archive | help
Here's what I used, plagiarized from other folks, natch. I figured the
risk of users sending their new password to the web gui was no worse
than them sending in POP passwords every 60 seconds. I do have the
poppasswd daemon on the same host as the web server which at least cuts
down on that risk.

Two parts, the HTML GUI, then the CGI to do the work. And you'll need
poppasswd of course. ISP name changed to protect the innocent :-)

--Chris

<HTML>
<HEAD>

<TITLE>Change Your Password</TITLE>
<BODY BGCOLOR="#ffffff" Text="#000000" Link="#0000bb" Vlink="#555555" Alink="#888888">
</HEAD>

<BODY>

<H1>Change Your Password</H1>

<p>You must be connected through ispdomain.net to change your
password.  As a security measure however if you are not logged in
through ISPDOMAIN -- perhaps connecting from some foreign ISP -- then
you will not be able to access this page.



<h2>Identity Verification</h2>

In order for our network to verify your identity, please enter your
current password below.  An unauthorized person can not change your
password without your knowledge, should you leave your computer
unattended.


<form action="/cgi-bin/change-password.cgi" method="POST">

<table>
<tr>
    <td>Username:
    <td><input type=text name="username" size=8>
    <td>(all lower case, 8 characters or less)
<tr>
    <td>Current password:
    <td><input type="password" name="oldpasswd" size=8>
    <td>(mixed case, 8 characters or less)
</td>
</table>


<h2> Select A New Password </h2>

Now you must select a new password. Your password should be something
you will remember, but someone trying to break into your account would
find hard to guess. You can use any combination of 6 to 8 upper and
lower case letters, numbers, and punctuation. Please note that the
password is case sensitive, so 'HELLO' is different from 'hello' is
different from 'hElLo'.  <P>

<P><STRONG>Do not use your name, username, or anything else obvious as
a password!</STRONG>

<p>In fact, you should avoid using actual words at all.  You might
take two short words and combine them with a special character or
number, as in "robot4my', or 'eye-con'. You could also put together an
acronym that is special to you, such as 'Notfsw?' for 'None Of This
Fancy Stuff Works?" Of course, these examples are now BAD passwords,
since they are here.  


<p>Here are the basic system requirements for a new password.
The system may reject passwords that do not meet the requirements. The best
passwords consist of the following:

<UL>
<LI>Between 6 and 8 characters
<LI>At least one upper-case character, and one lower-case character
<LI>At least one non-alpha character, such as a number and/or
    character such as: !,@,#,$,%
<LI>Your username and variations of it should not used</UL>

<table>
<tr>
    <td>Enter new password:
    <td><input type="password" name="passwd" size=8>
    <td>(6-8 characters, mixed case, with non-alphabetics)
<tr>
    <td>Re-type new password:    
    <td><input type="password" name="passwd1" size=8>
    <td>(to verify you typed it exactly right)
</table>

<input type="submit" value="Change Password">
<input type = "reset" value = "Clear Fields">

</form>



</BODY>
</HTML>

--

#!/usr/bin/perl
# $Id: change-password.cgi,v 1.2 1999/02/22 15:44:33 chris Exp $
#
# Simple UNIX user password changer based on web GUI and poppassd daemon.
#
# 1999/02/13 Chris Shenton <chris@shenton.org> for ispdomain.net.
# Plagiarized from mp@atlantic.net 2/1/97
# (http://www.atlantic.net; works with ISPs/corporations/individuals)
# They plagiarized from Chris Candreva's "wwwpass"
# (http://www.westnet.com/providers/)
#
# For ispdomain.net we need to propagate the password file from the WWW/FTP
# machine to the to the SMTP/POP/IMAP and RADIUS boxes. Use the SSH-based
# script I wrote. Are there any risks I'm missing here?
#
# The CGI argument processing and socket to poppassd can probably be better
# done with modern Perl modules, but this has the advantage of not requiring
# any extra baggage in the customer's Perl installation.
###############################################################################

# Install the HTML somewhere like $WWWROOT/password/index.html
# so users can change via http://www.domain/password/
# I recommend you restrict access to the HTML, CGI, and poppassd daemon
# to the minimum set of hosts you can get by with. Else everyone on the net
# will try and break in through automated attacks.
#
# The web form GUI asks for username, old, and new passwords 
# then invokes a CGI which talks to the poppassd password-changing daemon
# from Qualcomm (Eudora authors).
#
# It uses your poppassd port to do the work, so it requires 
# you have it installed -- but that way it will honor any
# type of security checks you want/have implemented. 
# It also isolates your password changing from any server-specific 
# password database implementations like shadow password files,
# FreeBSD-style hash databases, etc.
#
# Note that non-SSL web forms basically send this sensitive information
# over the net in the clear, and the CGI will talk to the poppassd daemon
# in the clear if they're on different machines. This is a security
# vulnerability and you need to determine the risk relative to other risks
# at your site, e.g.: users sending POP passwords in the clear, changing
# passwords over unencrypted telnet links, etc.
#
# You will need to change the line with $poppassd_host= to your poppassd
# server.  This script can be run on a different machine than where
# the poppassd program resides; and you will have to change the
# "rawclient" line from rio.atlantic.net to match the hostname of the
# host this script runs from.
###############################################################################

$www_url="http://www.ispdomain.net/password/";	# Where the HTML form lives
$www_admin="www\@ispdomain.net"; # Whatever's right for you.
$poppassd_port=106;		# 106 is standard port for poppassd
$poppassd_host="localhost";	# localhost if httpd, poppassd on same box
$wwwcgi_host="localhost";	# wwwcgi_host should be localhost, or
#chop($wwwcgi_host=`hostname`);	# can get from UNIX hostname command
#print "wwwcgi_host=$wwwcgi_host"; # maybe ignored/defaulted later; see below

###############################################################################

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);	# Split the name-value pairs
foreach $pair (@pairs)
{
    ($name, $value) = split(/=/, $pair);
    # Stop people from using subshells to execute commands
    # Not a big deal when using sendmail, but very important
    # when using UCB mail (aka mailx).
    # This will strip ! from passwords, not good.
    #$value =~ s/~!/ ~!/g;
    # Un-Webify plus signs and %-encoding
    $value =~ tr/+/ /;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
    $name =~ tr/+/ /;
    $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    # Set each variable
    if ($name eq "username")
    {
	$n=$value;
    }
    if ($name eq "oldpasswd")
    {
	$op=$value;
    }
    if ($name eq "passwd")
    {
	$np=$value;
    }
    if ($name eq "passwd1")
    {
	$np1=$value;
    }
}

if ($np ne $np1)
{
    $line="New Passwords Don't Match.";
    &error_out;
}
if ($line = &password_weak($n, $np)) {
    &error_out;
}

($name,$alias,$proto)=getprotobyname("tcp");

# This doesn't seem to be necessary, and may tie code to hardwired server name.
($name,$alias,$type,$len,$rawclient)=gethostbyname($wwwcgi_host);
$clientaddr=pack("Sna4x8",2,0,$rawclient);

($name,$alias,$type,$len,$rawserver)=gethostbyname($poppassd_host);
$serveraddr=pack("Sna4x8",2,$poppassd_port,$rawserver);

socket(SOCKET,2,1,$proto) ||
    die "No socket";
bind (SOCKET,$clientaddr) ||
    die "Can't bind to socket to wwwcgi_host=$wwwcgi_host";
$cstat=connect(SOCKET, $serveraddr);
select(SOCKET);
$|=1;

if ($cstat != 0)
{
    &get_reply;
    print SOCKET "user $n\n";
    &get_reply;
    print SOCKET "pass $op\n";
    &get_reply;
    print SOCKET "newpass $np\n";
    &get_reply;
    select(STDOUT);
    printf("Content-type: text/html\n\n<HTML><HEAD>\n");
    printf("<TITLE>Change Password -- Success</TITLE></HEAD>\n");
    printf("<BODY><H1>Change Password -- Success</H1>\n");
    printf("Your password has been changed successfully.");
    printf("<p>Server reports: $line<BR>\n");
    printf("<hr><p>The password is now changed on the WWW and FTP servers. ");
    printf("The change will be propagated to the Dial-in and Mail servers ");
    printf("shortly.  Passwords are synchronized once an hour at 30inutes ");
    printf("past the hour; until that time you will have to use your old ");
    printf("password for Dial-in and Mail.");
    printf("</BODY></HTML>\n");
    exit(1);
}
else
{
    $line="Password Server is not responding.\n";
    &error_out;
}
close(SOCKET);
exit(1);

###############################################################################
# Security Policy: 6-8 chars, at least one non-alpha, no embedded username.

sub password_weak {
    local($Username, $Password)    = @_;
    local($c);

    if ((length($Password) < 6) || length($Password) > 8) {
        return("Password length must be between 6 and 8 characters.");
    }
    if ($Password =~ /$Username/i) {
	return("Password countains the username; too obvious");
    }
    $Username = join('', reverse(split(//, $Username)));
    #return("username-r=$Username, password=$Password");
    if ($Password =~ /$Username/i) {
	return("Password contains the reversed username; too obvious");
    }
    for ($c = 0; $c < length($Password); $c++) {
        if (substr($Password, $c, 1) =~ /[^a-zA-Z]/) {  # Found a non-alpha
            return();
        }
    }
    return("Password must contain at least one non-alphabetic character");
}

###############################################################################
sub get_reply 
{
    $line=<SOCKET>;
    $v=substr($line,0,3);
    if ($v ne "200")
    {
	&error_out;
    }
}

###############################################################################
sub error_out
{
    select(STDOUT);
    printf("Content-type: text/html\n\n<HTML><HEAD>\n");
    printf("<TITLE>Change Password -- Error Occurred</TITLE></HEAD>\n");
    printf("<BODY><H1>Change Password -- Error Occurred</H1>\n");
    printf("We were unable to change your password. Please read the ");
    printf("following diagnostic message: "); 
    printf("<p><blockquote>$line</blockquote>");
    printf("<p>Now return to <a href=$www_url>$www_url</a> and try again.");
    printf("<p>If you need additional assistance, please send e-mail to ");
    printf("the administrator <a href=mailto:$www_admin>$www_admin</a> ");
    printf("with the above diagnostic message.");
    printf("</BODY></HTML>\n");
    exit(1);
}



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-isp" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?lf4sd04ax7.fsf>