#!/usr/bin/perl -w
# This script was written by Michel Arboi <arboi@alussinan.org>
# (C) 2004
# You can distribute it under the terms of the GNU Public Licence (GPLv2)
#
# If you don't know what the GPL is, of if you question its validity, then
# consider that this licence is void and that this script is protected by
# French copyright laws. Too bad :-)

use Sys::Syslog;
use IO::Stty;
use Digest::MD5 qw(md5_hex);

sub find_prefix {
  my @l = split(':', $ENV{PATH});
  push @l, "/usr/local", "/usr", "/opt/nessus";
  foreach $p (@l) {
    $p =~ s,/s?bin$,,;
    return $p if (-f $p . "/etc/nessus/nessusd.conf" and
		  -d $p . "/var/nessus/users")
  }
  die "Cannot find where Nessus is installed\n";
}

$prefix = find_prefix;

openlog "nessus-chpw", "pid", LOG_AUTHPRIV or die "openlog: $!";

$| = 1;
print "Username: ";
$user = <>; chomp $user;
if ($user !~ '^[a-zA-Z0-9_-]+') {
  syslog LOG_WARNING, "Invalid username: %s", $user;
  die "Invalid username: $user";
}

$old_mode=IO::Stty::stty(\*STDIN,'-g');
IO::Stty::stty(\*STDIN,'-echo');	# Turn off echoing.
print "Old password: ";
$oldpass = <>; chomp $oldpass;
IO::Stty::stty(\*STDIN,$old_mode);
print "\nNew password: ";
IO::Stty::stty(\*STDIN,'-echo');	# Turn off echoing.
$newpass1 = <>; chomp $newpass1;
IO::Stty::stty(\*STDIN,$old_mode);	# Now restore the old mode.
print "\nRetype password: ";
IO::Stty::stty(\*STDIN,'-echo');
$newpass2 = <>; chomp $newpass2;
IO::Stty::stty(\*STDIN,$old_mode);
print "\n";

($newpass1 eq $newpass2) or die "Passwords do not match";

sleep 2; # against brute force attacks

$fname = $prefix . "/var/nessus/users/" . $user . "/auth/hash";
if (open F, "<$fname") {
  $h = <F>;
  chomp $h;
  ($hash, $seed) = split(/[ \t]+/, $h);
  $check = md5_hex($seed . $oldpass);
  if ($check ne $hash) {
    syslog LOG_WARNING, "bad password for user %s", $user;
    print "Invalid username or password\n";
    exit 1;
  }
} else {
  syslog LOG_WARNING, "Cannot open %s: %s", $fname, $!;
  $fname2 = $prefix . "/var/nessus/users/" . $user . "/auth/password";
  if (open F, "<$fname2") {
    $check = <F>;
    chomp $check;
    if ($check ne $oldpass) {
      syslog LOG_WARNING, "bad password for user %s", $user;
      print "Invalid username or password\n";
      exit 1;
    }
  } else {
    syslog LOG_WARNING, "Cannot open %s: %s", $fname2, $!;
    syslog LOG_WARNING, "No such  user: %s", $user;
    print "Invalid username or password\n";
    exit 1;
  }
}

close F;

if (! open F, ">$fname") {
  syslog LOG_ERR, "Cannot open %s: %s", $fname, $!;
  die "Cannot open $fname: $!";
}

$seed = "";
for ($i = 0; $i < 16; $i ++) {
  $seed .= chr(rand(95)+33);
}

$hash = md5_hex($seed . $newpass1);

print F "$hash $seed\n";
if (! close F) {
  syslog LOG_ERR, "Cannot close $fname: $!";
  warn "close $fname: $!";
} else {
  syslog LOG_NOTICE, "Password changed for user %s", $user;
  print "Password changed for user $user\n";
}

