#!/usr/bin/perl -w

# Created by P.Wieleba@iem.pw.edu.pl in 2004

use strict;
use Getopt::Std;
use FindBin;
use FindBin qw($RealBin);
use lib "$RealBin/";
use smbldap_tools;

# function declaration
sub exist_in_tab;

my %Options;

my $ok = getopts('f:r:w:h:o:s:?v', \%Options);
if ( (!$ok) || ($Options{'?'}) ) {
  print "Usage: $0 [-frwhosh?] username\n";
  print "  -?|-h show this help message\n";
  print "  -f full_name\n";
  print "  -r room_no\n";
  print "  -w work_ph\n";
  print "  -h home_ph\n";
  print "  -o other\n";
  print "  -s shell\n";
  print "  -v show modified user record\n";
  exit (1);
}


my $user;
my $pass;
if ( $< != 0 ) {
  my $current_user = getpwuid($<);
  if ($current_user and $ARGV[0] and $current_user ne $ARGV[0] ) {
    die "Only root can change other users inormation\n";
  }
} else {
  if ( $ARGV[0] ) {
    $user = $ARGV[0];
  }
  $pass = 1;
}

if (!defined($user)) {
  $user = getpwuid($<);
}

my ($dn,$ldap_master);
# First, connecting to the directory
if ($< != 0) {
  # non-root user
  if (!defined($pass)) {
    # prompt for password
    print "UNIX password: ";
    system "stty -echo" if (-t STDIN);
    chomp($pass=<STDIN>);
    system "stty echo" if (-t STDIN);
    print "\n";

    $config{masterDN}="uid=$user,$config{usersdn}";
    $config{masterPw}="$pass";
    $ldap_master=connect_ldap_master();
    $dn=$config{masterDN};
    if (!is_user_valid($user, $dn, $pass)) {
      print "Authentication failure\n";
      exit (10);
    }
  }
} else {
  # root user
  $ldap_master=connect_ldap_master();
  # test existence of user in LDAP
  my $dn_line;
  if (!defined($dn_line = get_user_dn($user))) {
    print "$0: user $user doesn't exist\n";
    exit (10);
  }
  $dn = get_dn_from_line($dn_line);
}

my %eng = (
	   'shell'  => 'User Shell',
	   'name'   => 'Full Name',
	   'office' => 'Room Number',
	   'wphone' => 'Work Phone',
	   'hphone' => 'Home Phone',
	   'other' => 'Other'
	  );

# obtain old values
my $entry = read_user_entry($user);
my $gecos = $entry->get_value('gecos');
my %old;
( $old{'name'},
  $old{'office'},
  $old{'wphone'},
  $old{'hphone'},
  $old{'other'}
) = split(/,/,$gecos);
$old{'shell'} = $entry->get_value('LoginShell');
# unbind from LDAP
$ldap_master->unbind();

foreach my $key (keys %old) {
  !defined($old{$key}) and $old{$key}="";
}

# read new values
my %new;
if ($Options{'f'}) {
  $new{'name'} = $Options{'f'};
}
if ($Options{'r'}) {
  $new{'office'} = $Options{'r'};
}
if ($Options{'w'}) {
  $new{'wphone'} = $Options{'w'};
}
if ($Options{'h'}) {
  $new{'hphone'} = $Options{'h'};
}
if ($Options{'o'}) {
  $new{'other'} = $Options{'o'};
}
if ($Options{'s'}) {
  $new{'shell'} = $Options{'s'};
}
if ( keys(%Options) < 1 or keys(%Options) == 1 and $Options{'v'} ) {
  print "Changing the user information for $user\n";
  print "Enter the new value, or press ENTER for the default\n";

  print " $eng{'shell'} [$old{'shell'}]:";
  $new{'shell'} = readline(*STDIN);
  print " $eng{'name'} [$old{'name'}]:";
  $new{'name'} = readline(*STDIN);
  print " $eng{'office'} [$old{'office'}]:";
  $new{'office'} = readline(*STDIN);
  print " $eng{'wphone'} [$old{'wphone'}]:";
  $new{'wphone'} = readline(*STDIN);
  print " $eng{'hphone'} [$old{'hphone'}]:";
  $new{'hphone'} = readline(*STDIN);
  print " $eng{'other'} [$old{'other'}]:";
  $new{'other'} = readline(*STDIN);
}


foreach my $key (keys %old) {
  if (!$new{$key}) {
    $new{$key} = $old{$key};
  }
}

# simple check of new values
foreach my $key (keys %new) {
  chop($new{$key}) if ( $new{$key}=~/\n$/ );
  if ($new{$key} =~ /^\s+$/ and $key ne 'shell') {
    $new{$key} = "";
  } elsif ($new{$key} =~ /^$/) {
    $new{$key} = $old{$key};
  } elsif ($key ne 'other' and $new{$key} =~ /.*,.*/) {
    print "Comma cannot be used with $key.\n";
    exit(6);
  }
  # $new{$key} eq "" 
}

# [TODO] check if shell really exists
if ( $new{'shell'} and !($new{'shell'}=~/^\/.+\/.+/)
     and ($old{'shell'}=~/^\/.+\/.+/)
   ) {
  $new{'shell'} = $old{'shell'};
} elsif ( $new{'shell'} and !($new{'shell'}=~/^\/.+\/.+/)
          or !$new{'shell'} and !$old{'shell'}
        ) {
  $new{'shell'} = '/bin/sh';
}

if ( !$new{'name'} ) {
  $new{'name'} = $user;
}

# prepare gecos field
$gecos = join(',',
	      ( $new{'name'},
		$new{'office'},
		$new{'wphone'},
		$new{'hphone'},
		$new{'other'}
	      )
             );

my @tmp = split(/\s+/,$new{'name'});
my $sn = $tmp[$#tmp];
pop(@tmp);
my $givenName = join(' ',@tmp);

$entry->replace( 'gecos' => $gecos );
$entry->replace( 'cn'    => $new{'name'} );

if ( exist_in_tab( [$entry->get_value('objectClass')],'inetOrgPerson') ) {
  if ( $sn ) {
    $entry->replace('sn' => $sn);
  } else {
    $entry->replace('sn' => $user);
  }
  if ( $givenName ) {
    $entry->replace('givenName' => $givenName);
  } else {
    $entry->get_value('givenName') and $entry->delete('givenName');
  }
  if ( $new{'office'} ) {
    $entry->replace('roomNumber' => $new{'office'});
  } else {
    $entry->get_value('roomNumber') and $entry->delete('roomNumber');
  }
  if ( $new{'wphone'} ) {
    $entry->replace('telephoneNumber' => $new{'wphone'});
  } else {
    $entry->get_value('telephoneNumber') and $entry->delete('telephoneNumber');
  }
  if ( $new{'hphone'} ) {
    $entry->replace('homePhone' => $new{'hphone'});
  } else {
    $entry->get_value('homePhone') and $entry->delete('homePhone');
  }
}				#end of inetOrgPerson
if ( $new{'shell'} ) {
  $entry->replace('loginShell' => $new{'shell'});
} else {
  $entry->get_value('loginShell') and $entry->delete('loginShell');
}

if ($Options{'v'}) {
  $entry->dump();
}
# bind to LDAP and update entry
$ldap_master = connect_ldap_master();
my $mesg = $entry->update($ldap_master);
if ($mesg->is_error()) {
  print "Error: " . $mesg->error() . "\n";
} else {
  print "LDAP updated\n";
}
$ldap_master and $ldap_master->unbind;

# Check if a $text element exists in @table
# eg. exist_in_tab(\@table,$text);
sub exist_in_tab
  {
    my($ref_tab,$text) = @_;
    my @tab = @$ref_tab;

    foreach my $elem (@tab) {
      if ( lc($elem) eq lc($text) ) {
	return 1;
      }
    }
    return 0;
  }

########################################

=head1 NAME

smbldap-chfn - change user real name, information and shell

=head1 SYNOPSIS

smbldap-chfn [-f full_name] [-r room_no] [-w work_ph] [-h home_ph]
[-o other] [-s login_shell] [-?] [-v]

=head1 DESCRIPTION

This command changes user gecos fields and login shell.
The normal user can change only the fields for his own account,
the super user may change the fiels for any account.

If none of the options are selected, the command is run
in an interactive mode for the current user account. User is
asked for all fields. To accept a default value you should 
just press <ENTER>, otherwise write text and press <ENTER>.

posixAccount objectClasses has to be present in the modified
entry. If inetOrgPerson objectClass is also present additional
attributes will be changed (givenName,sn,roomNumber,telephoneNumber,
homePhone)

-f full_name
       affected attributes: 'gecos', 'cn' (and 'givenName', 'sn'
       if inetOrgPerson is present) 

-r room_number
       affected attributes: 'gecos' (and 'roomNumber'
       if inetOrgPerson is present)

-w work_phone
       affected attributes: 'gecos' (and 'telephoneNumber'
       if inetOrgPerson is present)

-h home_phone
       affected attributes: 'gecos' (and 'homePhone'
       if inetOrgPerson is present)

-o other
       affected attributes: 'gecos'

-s login_shell
       affected attributes: 'loginShell'

-?     show the help message

-v     verbose - show modified user entry

=cut

#'

# The End

