#!/usr/local/bin/perl
#
# $Id: usermodify,v 1.17 2004/06/01 20:08:42 visick Exp $
#
# usermodify - edit a user in LDAP
#
# Copyright (C) 2002 Steven Barrus
# Copyright (C) 2002 Dana Dahlstrom
# Copyright (C) 2002 Robert Ricci
# Copyright (C) 2002 Spencer Visick
#
# See the AUTHORS file for contact info
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

use Getopt::Std;
use Term::ReadLine;

require 'usertools.ph';

use strict;
no strict "vars";

$term = new Term::ReadLine;

@fields = ( 'uid', 'userpassword', 'uidnumber', 'gidnumber', 
            'cn', 'gecos', 'homedirectory', 'loginshell',);
if ($config{user_attribute}){
  for (parse_csv($config{user_attribute})){
    push(@fields,$_)
  }
}

%special_sub = ( 'userpassword' => \&get_new_pass);
for (parse_csv($config{password_attribute})){
  $special_sub{$_} = \&get_new_pass;
}

# Check for -h
if ($ARGV[0] =~ /^-h/) {
  exit &usage;
}

# Connect to the LDAP server
$ldap = ldap_connect() || exit(1);

if (@ARGV) {
  foreach (@ARGV) {
    if ($_ =~ /(.+)=(.*)/){
      $attrs{$1} = $2;
    } else {
      push(@users,$_);
    }
  }
  if (keys(%attrs)){
    foreach (@users) {
      &setattr($_);
    }
  } else {
    foreach (@users) {
      &chentry($_);
    }
  }
} else {
  while (1) {
    print "Lookup entry for username (blank to end): ";
    $user = <STDIN>;
    chomp $user;
    if ($user) {
      &chentry($user);
    } else {
      last;
    }
  }
}

sub chentry {
  $user = shift;

  $search = "(uid=" . $user . ")";

  $mesg = $ldap->search( base => $config{userbase}, filter => $search);
  $entry = $mesg->entry(); 

  if ($entry) {
    print "Found LDAP entry for $user\n";
  } else {
    print "Unable to find LDAP entry for $user\n";
    return 0;
  }

  while (1) {
    print "\n";
    $index = 1;
    foreach ( @fields ) {
      $aref = $entry->get_value($_, asref => 1);
      printf("%2d)%20s: ",$index++,$_);
      if ($aref) {
        print join ", ", @$aref;
      }
      print "\n";
    }
    print " C)ancel all changes\n";
    print " S)ave changes\n";
    print " E)xop set password\n" if $config{version} > 2;
    print " D)elete this user\n";
    
    print "\nSelection? ";
    $choice = lc(<STDIN>);
    chomp $choice;

    # C)ancel all changes
    if ($choice =~ /^c/) {
      return;
    }

    # D)elete this user
    if ($choice =~ /^d/) {
      print "Really delete $user? [y/N] ";
      $choice = lc(<STDIN>);
      if ($choice =~ /^y/) {
        print "NOTE: This function does NOT delete the user's home directory, mail file, etc.\n";
        $mesg = $ldap->delete($entry);
        warn $mesg->error . "\n" if $mesg->code;
        return;
      } else {
        next;
      }
    }

    # S)ave changes and exit
    if ($choice =~ /^s/) {
      if ($changed){
        $mesg = $entry->update($ldap);
        warn $mesg->error . "\n" if $mesg->code;
      }
      $changed = undef;
      return;
    }

    # E)xop set password
    if ($choice =~ /^e/) {
      $value = get_new_pass_plain();
      $mesg = $ldap->set_password( user=> $entry->dn, newpasswd => $value );
      warn $mesg->error . "\n" if $mesg->code;
      next;
    }

    next if ($choice eq "" or $choice < 1);

    $field = $fields[$choice-1];
    $changed = 1;

    if ($special_sub{$field} and $choice !~ /^0/) {
      $value = &{$special_sub{$field}};
    } else {
      $value = $term->readline("$field: ", $entry->get_value($field));
    }

    if ($value) {
      $mesg = $entry->replace($field => $value);
    } else {
      $mesg = $entry->delete($field);
    }

  }
}

sub setattr {
  $user = shift;

  $search = "(uid=" . $user . ")";

  $mesg = $ldap->search( base => $config{userbase}, filter => $search);
  $entry = $mesg->entry(); 

  if (!$entry) {
    print "Unable to find LDAP entry for $user\n";
    return 0;
  }
  foreach $field (keys(%attrs)){
     if ($attrs{$field}) {
       $mesg = $entry->replace($field => $attrs{$field});
     } else {
       $mesg = $entry->delete($field);
     }
  }
  $mesg = $entry->update($ldap) ;
  warn $mesg->error . "\n" if $mesg->code;
  return;
}


sub usage {

  print << "EOSTR";

Usage: $0 [usernames]

If usernames are given on the command line, the user will be prompted for
the LDAP password, and modifications for those usernames.

If no username is given, $0 will enter a loop, 
prompting for usernames to modify.

EOSTR

  1;
}
__END__
=head1 NAME

usermodify - edit a user in LDAP

=head1 SYNOPSIS

B<usermodify> [usernames]

B<usermodify> [usernames] [attr=value] ...

B<usermodify> [-h]
     

=head1 DESCRIPTION

B<usermodify> allows changes to a user in the LDAP directory 
specified in /etc/usertools.conf or $HOME/.usertoolsrc. 
You will be prompted for a password with which to bind. If no 
user name is given, B<usermodify> will enter a loop, prompting 
for users.

If I<attr=value> pair is given the attribute will be silently 
updated for all users specified on the command line. If no user
name is specified, no attributes will be modified.

You may edit cn, uid, userpassword, uid number, gid number, 
gecos, home directory, shell, and any custom attribute
in the list user_attribute in your configuration file.

=head1 OPTIONS

B<-h>

Print out usage information.

=head1 BUGS

lots probably, sorry. Contact usertools-bugs@nongnu.org if you find any.

=head1 AUTHORS

The usertools were written at the CADE by various opers. See the AUTHORS file 
for details.

=head1 SEE ALSO

usercreate(1), usermodify(1), userrevert(1), usersearch(1), userdelete(1),
groupcreate(1), groupsearch(1), groupmodify(1).


=cut 


