#!/usr/bin/perl
##
## FIXME: まったく動作テストしていない
##

use strict;
use warnings;
use English;
use IO::File;
use Encode;
use Text::CSV_XS;
use Crypt::SmbHash;

use smbldap_tools;

## ======================================================================

use constant SMBLDAP_USERADD_CMD => '/usr/sbin/smbldap-useradd';
use constant NAME_MAXLEN => 20;
use constant REALNAME_MAXLEN => 256;
use constant DESC_MAXLEN => 48;

my $flag_run = !$ENV{'SMBCSV_USERADD_DRYRUN'};
my $csv_encoding = $ENV{'SMBCSV_USERADD_CSV_ENCODING'} || 'CP932';

## ======================================================================

my $ldap = $flag_run ? smbldap_tools::connect_ldap_master : 'Dry Run';
my $csv = Text::CSV_XS->new({'binary' => 1});

STDIN->getline; ## Discard the header line
while (defined(my $csv_line = STDIN->getline)) {
  my $line = 'Line ' . (STDIN->input_line_number - 1);

  my $name = eval {
    eval {
      Encode::from_to($csv_line, $csv_encoding, 'UTF-8');
    };
    if ($EVAL_ERROR) {
      die "cannot convert input encoding: $EVAL_ERROR";
    }

    if (!$csv->parse($csv_line)) {
      die "cannot parse input as CSV format";
    }

    my ($name, $pwd, $realname, $desc) = map { /^\s*(.*)\s*$/ } $csv->fields;

    if ($name =~ /^[#;]/) {
      ## This is comment, I love comment.
      exit;
    }

    if ($name !~ /^[a-z_][\w\-.]*$/) {
      die "invalid username format: $name";
    }
    if (length($name) > NAME_MAXLEN) {
      die "username too long (>" . NAME_MAXLEN . "): $name";
    }
    if (getpwnam($name) || getgrnam($name)) {
      die "user already exists: $name";
    }

    if (length($realname) > REALNAME_MAXLEN) {
      die "real name too long (>" . REALNAME_MAXLEN . "): $realname";
    }
    if (length($desc) > DESC_MAXLEN) {
      die "description too long (>" . DESC_MAXLEN . "): $desc";
    }

    my ($lmpwd_hash, $ntpwd_hash) = Crypt::SmbHash::ntlmgen($pwd);

    unless ($flag_run) {
      $lmpwd_hash =~ s/^(.{8})(.*)$/$1 . '*' x length($2)/e;
      $ntpwd_hash =~ s/^(.{8})(.*)$/$1 . '*' x length($2)/e;
      print "$line: ", join(', ',
	"name=$name",
	"pwd=$pwd",
	"realname=$realname",
	"desc=$desc",
	"lmpwd_hash=$lmpwd_hash",
	"ntpwd_hash=$ntpwd_hash",
      ), "\n";
      exit;
    }

    my @useradd_opts = (
      '-a',
      #'-u', $uid, FIXME
      $name,
    );
    system(SMBLDAP_USERADD_CMD, @useradd_opts);
    if ($CHILD_ERROR) {
      die SMBLDAP_USERADD_CMD . ' failed: status ' . ($CHILD_ERROR >> 8);
    }

    my $entry = smbldap_tools::read_user_entry($name);
    if (!defined($entry)) {
      die SMBLDAP_USERADD_CMD . ' succeeded, but cannot read entry for user';
    }

    my %replace = ();
    $replace{'displayName'} = $realname if ($realname);
    $replace{'description'} = $desc if ($desc);
    $replace{'sambaNTPassword'} = $ntpwd_hash if ($ntpwd_hash);
    $replace{'sambaLMPassword'} = $lmpwd_hash if ($lmpwd_hash);

    if (%replace) {
      my $mesg = $ldap->modify($entry->dn, 'replace' => \%replace);
      if ($mesg->code) {
	die 'cannot adjust attribute for user: ' . $mesg->error;
      }
    }

    return $name;
  };
  if ($EVAL_ERROR) {
    print "$line: ERROR: $EVAL_ERROR";
    next;
  }

  print "$line: OK: $name\n";
}

