#!/usr/bin/perl
#
# Windowsパスワード変更スクリプト
#
# Copyright(c) SECIOSS CORPORATION 2009
#

use strict;
use Net::LDAP;
use Net::LDAP::Constant qw(:all);
use Getopt::Std;
use Config::IniFiles;
use MIME::Base64;
use Sys::Syslog;
use Sys::Syslog qw(:macros);
use Data::Dumper;

my %opt;
getopts("f:H:b:D:s:u:p:S", \%opt);

sub delquote
{
    my ($str) = @_;

    $str =~ s/^["']*//;
    $str =~ s/["']*$//;

    return $str;
}

# Configuration
my $file;
if ($^O ne 'MSWin32') {
    $file = '/var/www/conf/config.ini';
} else {
    $file = '/secioss/var/www/conf/config.ini';
}
if (defined($opt{'f'})) {
    $file = $opt{'f'};
}

my $uri;
my $basedn;
my $binddn;
my $bindpw;
my $userattr;
my $pwdattr;

my $config;
if (-f $file) {
    $config = Config::IniFiles->new(-file => $file);

    $uri = delquote($config->val('password', 'uri'));
    $basedn = delquote($config->val('password', 'basedn'));
    $binddn = delquote($config->val('password', 'binddn'));
    $bindpw = delquote($config->val('password', 'bindpw'));
    $userattr = delquote($config->val('password', 'userattr'));
    $pwdattr = delquote($config->val('password', 'pwdattr'));
}
$uri = defined($opt{'H'}) ? $opt{'H'} : $uri;
$basedn = defined($opt{'b'}) ? $opt{'b'} : $basedn;
$binddn = defined($opt{'D'}) ? $opt{'D'} : $binddn;
$bindpw = defined($opt{'s'}) ? $opt{'s'} : $bindpw;
$userattr = defined($opt{'u'}) ? $opt{'u'} : $userattr;
$pwdattr = defined($opt{'p'}) ? $opt{'p'} : $pwdattr;
$userattr = $userattr ? $userattr : 'uid';
$pwdattr = $pwdattr ? $pwdattr : 'userPassword';

my $LOG_FACILITY = 'local5';
my $LOG_LEVEL = LOG_DEBUG;

# open syslog
openlog('chwinpasswd', 'pid', $LOG_FACILITY);
setlogmask(Sys::Syslog::LOG_UPTO($LOG_LEVEL));

my $dn = $ARGV[0];
my $newpasswd = decode_base64($ARGV[1]);
my $oldpasswd = decode_base64($ARGV[2]);

my $ldap = Net::LDAP->new($uri);
if (!defined($ldap)) {
    syslog(LOG_CRIT, "Can't connect to LDAP server");
    exit LDAP_SERVER_DOWN;
}

my $msg = $ldap->bind($binddn, password => $bindpw);
if ($msg->code) {
    syslog(LOG_CRIT, "Can't bind to LDAP server(".$msg->code.")");
    exit LDAP_OTHER;
}

if (defined($opt{'S'})) {
    $msg = $ldap->search(base => $basedn, filter => "($userattr=$dn)", attrs => ['dn']);
    if ($msg->code) {
        syslog(LOG_ERR, "Can't search user $dn(".$msg->code.")");
        exit $msg->code;
    } elsif ($msg->count == 0) {
        syslog(LOG_INFO, "User $dn doesn't exist");
        exit 0;
    } elsif ($msg->count != 1) {
        syslog(LOG_ERR, "User $dn isn't unique");
        exit LDAP_OTHER;
    }

    my $entry = $msg->entry(0);
    $dn = $entry->dn;
}

# check operation
if (!$dn || !$newpasswd || !$oldpasswd) {
    syslog(LOG_ERR, "Ivalid password");
    exit LDAP_UNWILLING_TO_PERFORM;
}

$msg = $ldap->modify($dn, changes => [
                          delete => [$pwdattr => $oldpasswd],
                          add => [$pwdattr => $newpasswd]]);
if ($msg->code) {
    syslog(LOG_ERR, "User $dn can't modify password(".$msg->code.")");
}
$ldap->unbind;

exit $msg->code;
