#! /usr/local/bin/perl -w # # ldap_mod_attr - change an attribute in someone's LDAP entry # # Author: Andrew J Cosgriff # Created: Thu Dec 4 19:48:03 1997 # Version: $Id: lma,v 1.1 1999/04/05 09:35:51 ajc Exp $ # Keywords: ldap modify add remove attribute commmand-line useful really # ######################################## # ### Commentary: # # Sick of typing in lines of ldapmodify stuff just to change one or # two attributes ? This is for you... # ### TO DO: # # - we don't deal with things that already have multiple values # for the same attribute. be careful here ! # ######################################## # ### Code: # use Net::LDAPapi; use Getopt::Std; use File::Basename; my $version = substr q$Revision: 1.1 $, 10; chop $version; ########## # # Defaults - EDIT THESE TO SUIT YOUR ENVIRONMENT ! # $ldap_server = "ldap.yoursite.com"; $BASEDN = $ENV{'LDAP_BASEDN'} || "o=My Organization, c=AU"; $ROOTDN = "cn=Directory Manager"; $ROOTPW = ""; $batchmode = 0; $verbosemode = 0; $modify_all = 0; $do_nothing = 0; $UIDATTR = "uid"; # # Parse command line options, explained here : # $usage_msg = "ldap_mod_attr version " . $version . " by Andrew J Cosgriff Usage : " . basename($0) . " [options] ... [options] being one or more of : -a : modify all matching entries (rather than prompting for one) -b : base DN for searches [ default - $BASEDN ] -D : bind as this DN to do the modifications [ default - $ROOTDN ] -h : ldap server to talk to [ default - $ldap_server ] -n : do nothing, just show what would happen (implies -v) -q : batch/quiet mode - no prompting for password - no prompting if there are multiple matches -v : verbose mode - print \" changed from to \" -w : the password for the DN we bind as with -D being either : - a uid, eg. \"nate\" - an RFC 1558-style LDAP search filter, eg. \"cn=Nathan Bailey\" exitcodes are : 1 - general error 2 - no matches returned by ldap_search_s 3 - too many matches (for -q) "; if (getopts('ab:D:h:nqvw:?', \%opt) == 0) { print $usage_msg; exit 1; } $modify_all = 1 if (defined $opt{'a'}); $BASEDN = $opt{'b'} if (defined $opt{'b'}); $ROOTDN = $opt{'D'} if (defined $opt{'D'}); $ldap_server = $opt{'h'} if (defined $opt{'h'}); $batchmode = 1 if (defined $opt{'q'}); $verbosemode = 1 if (defined $opt{'v'}); $do_nothing = 1 if (defined $opt{'n'}); $verbosemode = $do_nothing || $verbosemode; $ROOTPW = $opt{'w'} if (defined $opt{'w'}); # # Print help if they want/need it # if ($opt{'?'}) { print $usage_msg; exit 1; } if ($#ARGV == -1) { print "Need to specify a search filter and attr=value pairs\n"; print $usage_msg; exit 1; } if ($#ARGV <= 0) { print "Need to specify attr=value pairs as well\n"; print $usage_msg; exit 1; } print "Well hey, we\'re in DoNothing mode...\n" if $do_nothing; print "Connecting to $ldap_server\n"; # # Ask for the Root DN's password if they didn't specify it # if ($ROOTPW eq "") { print "Attempting to bind as $ROOTDN\nPassword : "; system "stty -echo"; $ROOTPW = ; chomp $ROOTPW; system "stty echo"; print "\n"; } # # Initialize Connection to LDAP Server # if (($ld = ldap_open($ldap_server,LDAP_PORT)) eq "") { die "ldap_init failed"; } # # Bind as the specified DN # if ((ldap_simple_bind_s($ld,$ROOTDN,$ROOTPW)) != LDAP_SUCCESS) { ldap_perror($ld,"ldap_simple_bind_s"); die "Failed to bind as $ROOTDN"; } # # Perform search # $filter = shift @ARGV; if ($filter !~ /[\(\)\&\|=]/) { $filter = "($UIDATTR=$filter)"; } print "\nSearching for $filter\n" if ($verbosemode); @attrs = (); if (ldap_search_s($ld,$BASEDN,LDAP_SCOPE_SUBTREE,$filter,\@attrs,0,$result) != LDAP_SUCCESS) { $err = ldap_get_lderrno($ld,$errdn,$extramsg); print &ldap_err2string($err),"\n"; print "DN $errdn\n" if defined $errdn; print "extramsg $extramsg\n" if defined $extramsg; ldap_unbind($ld); die "Search for $filter failed\n"; } $num_entries = ldap_count_entries($ld,$result); # # Die if we got no matches, or if we're in batch mode and got more # than one match # exit 2 if ($num_entries == 0); exit 3 if ($batchmode && ($num_entries > 1)); print "$num_entries matches\n" if ($verbosemode && ($num_entries > 1)); $entry = ldap_first_entry($ld, $result); if ($num_entries == 1) { # # If we got just one match, just do it. # &do_mod_entry($entry); } else { # # If we're modifying all entries, loop through and do each one in # turn. Otherwise, make a list of entries so we can present a menu # and ask the user which entry to modify. # while ($entry != 0) { if ($modify_all) { &do_mod_entry($entry); } else { push @entries, $entry; } $entry = ldap_next_entry($ld, $entry); } # # Present a menu of matching entries, and ask which of them the user # wants to modify. # if (! $modify_all) { for $cnt (0 .. $#entries) { print "$cnt : ", ldap_get_dn($ld, $entries[$cnt]), "\n"; } $num = -1; while (($num < 0) || ($num > $#entries)) { print "Which entry ? : "; $num = ; chomp $num; } &do_mod_entry($entries[$num]); } } ######################################## # # do_mod_entry - Given an entry (as returned by # ldap_first_entry/ldap_next_entry), apply all the modifications as # specified in @ARGV # sub do_mod_entry { my $entry = shift @_; my $dn = ldap_get_dn($ld, $entry); print "\nModifying ", ldap_get_dn($ld, $entry), " :\n" if $verbosemode; foreach $mod (@ARGV) { my ($attr, $val) = split('=',$mod); @values = ldap_get_values($ld,$entry,$attr); my (%mods) = ( $attr, $val ); if (($#values > -1) && ($val eq $values[0])) { print "* (no change) $attr=$val\n" if $verbosemode; next; } elsif (($#values == -1) && ($val eq "")) { print "* (no change) $attr not present\n"; next; } # # Print out nice verbose info on what's going on # if ($verbosemode) { if ($val eq "") { if ($#values > -1) { print "- $attr=", $values[0], "\n"; } } elsif ($#values > -1) { print "- $attr=", $values[0], "\n"; print "+ $attr=", $val, "\n"; } else { print "+ $attr=$val\n"; } } # # Apply this modification - it'd be groovier to assemble a list of # modifications so we only call ldap_modify_s once per entry, but # it's a bit fiddly to assemble said list properly, so i'm being # lazy :) # if (! $do_nothing) { if (ldap_modify_s($ld,$dn,\%mods) != LDAP_SUCCESS) { ldap_perror($ld,"ldap_modify_s"); die "Failed to modify $dn\n"; } else { print "* modifications successful.\n" if $verbosemode; } } } } ### ldap_mod_attr ends here