Changing Passwords via CGI

2007-12-25 11:40:00

>

>I have just inherited a large group of new UNIX "illiterate" users

>that will be working under a restricted environment. Instead of

>attempting to train/teach these people how to change their password

>and giving them access to the shell, does any one have a CGI script

>that allows one to change their password via the web ?

>

Sorry it has taken so long but this was item 10 on the to do list and

I had to make sure I could also get a version working for HP-UX 10.2

and for NIS. Included at the bottom is the Perl 5 source for the the

Solaris passwd version. If you want a Solaris NIS or HP-UX 10.2

version let me know.

The program is originally from the Perl Journal, Summer 98 written by

Lincoln D Stein. I have modified it to use the expect module instead

of the chat2 module as he mentioned in the article.

Many thanks to Jeff Putsch <putsch@unitrode.com> for pointing me to

the article.

Other suggestions were discarded for various reasons:

- Set the shell for passwd. Unfortunately the users still have to log

in.

- Use Expect. I sort of do in this script by using the expect module.

- Use an interface to the popassd program called wwwpass. Since I

didn't want another daemon to mess around with I didn't use this

avenue. Also the program set found at

ftp://ray.ucs.sfu.ca/Public/Account_Management/management.tar and

ftp://ray.ucs.sfu.ca/Public/Account_Management/lib.tar.

Thanks to:

Rik Schneider <rik@netasset.com>

Chris Tubutis <chris@tci.com>

Robert Rose <Robert.Rose@ag.gov.au>

Mick Morgan <sun-managers@open.gov.uk>

Richard Bosire <bosire@ns1.africaonline.co.ke>

agardine@lsil.com <Alistair Gardiner>

Bjorn E. Torsteinsen <Bjorn.Torsteinsen@nfh.uit.no>

Jeff Putsch <putsch@unitrode.com>

Ken McKinlay

Unix Administrator

Lockheed Martin Canada, Kanata

(613) 599-3280 x861

Ken.McKinlay@lmco.ca

------------------

#!/usr/local/bin/perl5

# preliminaries to satisfy taint checks

$ENV{PATH} = '/bin:/usr/bin';

$ENV{IFS} = '';

# Prevent buffering problems

$| = 1;

use CGI qw/:standard :html3/;

# display the HTML header

print header,

        start_html(-title=>'Change Unix Password',

                -bgcolor=>'white'),

        h1('Change your Unix password');

import_names('Q');

TRY: {

    last TRY unless $Q::user;

    my ($rv,$msg) = check_consistency();

    do_error($msg),last TRY unless $rv;

    ($rv,$msg) = set_passwd($Q::user,$Q::old,$Q::new1);

    do_error($msg),last TRY unless $rv;

    print $msg;

    $OK++;

}

create_form() unless $OK;

print

        p,

        a({href=>"$Q::referer" || referer() },"[ EXIT SCRIPT]"),

        hr,

        a({href=>'/'},'Home page'),

        end_html;

sub check_consistency {

    return (undef,'Please fill in the user name field.') unless $Q::user;

    return (undef,'Please fill in the old password field.') unless $Q::old;

    return (undef,'Please fill in the new password fields.') unless $Q::new1 &&

$Q::new2;

    return (undef,"New password fields don't match.") unless $Q::new1 eq

$Q::new2;

    return (undef,"Suspicious user name $Q::user.") unless

$Q::user=~/^\w{3,8}$/;

    return (undef,'Suspiciously long old password.') unless length($Q::old) <

30;

    return (undef,'Suspiciously long new password.') unless length($Q::new1) <

30;

    my $uid = (getpwnam($Q::user))[2];

    return (undef,"Unknown user name $Q::user.") if $uid eq '';

    return (undef,"Can't use this script to set root password.") if $uid == 0;

    return 1;

}

sub set_passwd ($$$) {

    use Expect;

    $Expect::Log_Stdout = 0;

    my $TIMEOUT = 2;

    my $PASSWD = "/bin/passwd";

    my $SU = '/bin/su';

    my($user,$old,$new) = @_;

    # spawn the su command using expect

    my $passwd = Expect->spawn("$SU $user -c \"$PASSWD $user\"") || return

(undef,"Couldn't open $SU $user -c $PASSWD");

    # wait for su to prompt for password

    my $rv = $passwd->expect($TIMEOUT,

                        "Password:",

                        "su: Unknown id: $user");

    $rv == 2 && return (undef,"User $user unknown.");

    $rv || return (undef,"Didn't get su password prompt.");

    # send the password for the user

    print $passwd "$old\r";

    # wait for passwd to prompt for old password

    $rv = $passwd->expect($TIMEOUT,

                        "Old password:",

                        "su: Sorry");

    $rv == 2 && return (undef,"Old password is incorrect.");

    $rv || return (undef,"Didn't get prompt for old password.");

    # print old password

    print $passwd "$old\r";

    $rv = $passwd->expect($TIMEOUT,

                        "New password:",

                        "Sorry.");

    $rv == 2 && return (undef,"Old password is incorrect.");

    $rv || return (undef,"Timed out without seeing prompt for new password.");

    # print new password

    print $passwd "$new\r";

    $rv = $passwd->expect($TIMEOUT,

                        "Re-enter new password:",

                        "Please use a longer password.",

                        "Passwords must differ by at least 3 positions",

                        "Password must contain at least two alphabetic

characters and at least one numeric or special character.");

    $rv == 2 && return (undef,"Please use a longer password.");

    $rv == 3 && return (undef,"Passwords must differ by at least 3 positions.");

    $rv == 4 && return (undef,"Password must contain at least two alphabetic

characters and at least one numeric or special character.");

    $rv || return (undef,"Timed out without seeing second prompt for new

password.");

    # reconfirm password

    print $passwd "$new\r";

    $rv = $passwd->expect($TIMEOUT,

                        "They don't match; try again.");

    $rv == 1 && return (undef,"Second password doesn't match.");

    $passwd->hard_close();

    return (1,"Password changed successfully for $Q::user.");

}

sub create_form {

    print

        start_form,

        table(

              TR({align=>RIGHT},

                 th('User name'), td(textfield(-name=>'user')),

                 th('Old password'),td(password_field(-name=>'old'))),

              TR({align=>RIGHT},

                 th('New password'),td(password_field(-name=>'new1')),

                 th('Confirm new password'),td(password_field(-name=>'new2'))),

              ),

        p,

        hidden(-name=>'referer',-value=>referer()),

        table(

              TR(

                 td({align=>LEFT},submit('Change Password')),

                 td({align=>RIGHT},reset)),

              ),

        end_form;

}

sub do_error ($) {

    print "<CENTER><FONT COLOR='red' SIZE='+1'>";

    print b('Error: '),shift," Password is not changed.";

    print "</FONT></CENTER>";

}

Comments

Got something to say?

You must be logged in to post a comment.