#!/usr/bin/perl
############################################################################
# Simple CGI script that uses smbpasswd to allow a user to change their
# password on a Windows domain controller.
#
# Written 2013-03-02 by Lester Hightower
############################################################################
use strict;
use CGI qw(:standard);
use IPC::Open3;
use Symbol 'gensym';
my $DOM_CONTROLLER = '10.113.20.20';
my $EXE_SMBPASSWD = '/usr/bin/smbpasswd';
my $q = CGI->new;
if (uc($q->request_method()) eq 'POST') {
  try_change_passwd($q);
} else {
  send_change_form($q);
}
exit;
############################################################################
############################################################################
############################################################################
sub send_change_form($) {
  my $q=shift @_;
  print $q->header('text/html');
  my @form_elements = (
        { 'name' => 'Username', 'html' =>
    textfield(-name=>'username', -value=>'',-size=>20,-maxlength=>80)
        },
        { 'name' => 'Current Password', 'html' =>
    password_field(-name=>'old_passwd', -value=>'',-size=>20,-maxlength=>80),
        },
        { 'name' => 'New Password', 'html' =>
    password_field(-name=>'new_passwd', -value=>'',-size=>20,-maxlength=>80),
        },
        { 'name' => 'Retype new password', 'html' =>
    password_field(-name=>'new_passwd2', -value=>'',-size=>20,-maxlength=>80),
        },
        );
  print
    "\n" .
    "
Change your Windows domain password\n" .
    "\n" .
    "Change your Windows domain password
\n" .
    start_form(-method=>'POST') .
    "\n" .
    make_form_table_fields($q, \@form_elements) .
    "| " .
        submit(-name=>'btn_chpasswd', -value=>'Change Password') .
        " | 
\n" .
    "
\n" .
    end_form .
    "\n" .
    "\n";
  return;
}
sub make_form_table_fields($$) {
  my $q=shift @_;
  my $form_elements=shift @_;
  my $t='';
  foreach my $fe (@{$form_elements}) {
    my $name=$fe->{name};
    my $html=$fe->{html};
    $t.="| $name | $html | 
\n";
  }
  return $t;
}
############################################################################
sub try_change_passwd($) {
  my $q=shift @_;
  print $q->header('text/html');
  my $username = $q->param('username');
  my $old_passwd = $q->param('old_passwd');
  my $new_passwd = $q->param('new_passwd');
  my $new_passwd2 = $q->param('new_passwd2');
  if ($username !~ m/^[a-z._0-9]+$/i) {
    print "Invalid username\n";
    return;
  }
  if (length($new_passwd) < 1) {
    print "New password cannot be blank.\n";
    return;
  }
  if ($new_passwd ne $new_passwd2) {
    print "Mismatch in new password verification.\n";
    return;
  }
  my($wtr, $rdr, $err);
  $err = gensym;
  my @cmd=($EXE_SMBPASSWD,'-s','-U',$username,'-r',$DOM_CONTROLLER);
  #warn "LHHD: running - " . join(" ", @cmd) . "\n";
  my $pid = open3($wtr, $rdr, $err, @cmd);
  print $wtr "$old_passwd\n$new_passwd\n$new_passwd2\n";
  waitpid( $pid, 0 );
  my $child_exit_status = $? >> 8;
  if ($child_exit_status == 0) {
    print "Password changed successfully.";
  } else {
    my $stdout=<$rdr>;
    my $stderr=<$err>;
    my $errmsg=$stdout;
    if (length($errmsg)) { $errmsg .= "\n-\n"; }
    $errmsg .= $stderr;
    print "Password change was not successful:$errmsg
\n";
  }
  return;
}