[helpers from ldap/scripts Panu Kalliokoski **20151116134854 Ignore-this: 2d9e3dd4b98f50e1052134f66c24fa7d ] adddir ./clients/helpers addfile ./clients/helpers/askare_sql hunk ./clients/helpers/askare_sql 1 +#!/bin/bash + +# This script gives an interactive SQL monitor for Sybase/MSSQL servers. +# It uses the bsqldb program from FreeTDS. + +test "X$1" = X && rlwrap $0 --interactive && exit 0 +test "X$DBHOST" = X && echo "Please specify DBHOST in environment" && exit 1 +test "X$DBUSER" = X && echo "Please specify DBUSER in environment" && exit 1 +test "X$DBDB" = X && echo "Please specify DBDB in environment" && exit 1 + +read -p "Give DB password: " -s PASSWORD && echo + +exec_sql() { + echo "$*" | \ + bsqldb -h -t '|-|' -S "$DBHOST" -D "$DBDB" -U "$DBUSER" -P "$PASSWORD" +} + +to_html() { + echo '' + sed 's#&#\&#g;s#<#\<#g;s#>#\>#g' | \ + sed 's#^##;s#|-|#\(
#;s#$#
#g' | \ + sed '/
-*<\/td>\)*<\/tr>/{;s#.*#
#p;d;};${;x;p;};x' + echo '
' +} + +while true; do + read -p "sql> " QUERY + exec_sql "$QUERY" | to_html | w3m -dump -T text/html +done + addfile ./clients/helpers/crypt.c hunk ./clients/helpers/crypt.c 1 +#define _XOPEN_SOURCE +#include +#include +#include + +int main(int ac, char *av[]) +{ + if (ac < 3) exit(1); + printf("%s crypted by salt %s: %s\n", + av[1], av[2], crypt(av[1], av[2])); + return 0; +} + addfile ./clients/helpers/csvread.py hunk ./clients/helpers/csvread.py 1 +#!/usr/bin/env python +# A helper script to print the contents of a specific column from headerful CSV +# Called as: csvread.py 'Field name' data.csv + +from pprint import pprint +from csv import DictReader +import sys + +progname, fieldname, filename = sys.argv + +with open(filename, "rb") as csvfile: + for recipient in DictReader(csvfile, delimiter=';', quotechar='"'): + print recipient[fieldname] + addfile ./clients/helpers/fetch_dump.sh hunk ./clients/helpers/fetch_dump.sh 1 +#!/bin/bash + +usage () { + cat 1>&2 <&2 ; usage ;; + + *) TREE="$1" ;; + + esac + shift +done + +test -z "$TREE" \ + && echo "Please give an LDAP(s) URI for me" 1>&2 && exit 1 +test -z "$BINDACCT" \ + && echo "Please define BINDACCT in environment" 1>&2 && exit 1 + +BASE=`echo "$TREE" | cut -d/ -f4-` +URL=`echo "$TREE" | cut -d/ -f1-3` +HOST=`echo "$TREE" | cut -d/ -f3 | cut -d: -f1` + +test -z "$USE_LOCALHOST" || URL=`echo "$URL" | sed "s/$HOST/localhost/"` + +LDAP="ldapsearch -x -H '$URL' -D '$BINDACCT' -W -b '$BASE' '(objectClass=*)'" +if test -z "$NO_SSH"; then + LDAP="ssh -t $HOST $LDAP" +else + LDAP="eval $LDAP" +fi + +mkdir -p dumps +test -z "$DUMPFILE" && DUMPFILE="dumps/dump-$HOST-`date +%Y%m%d`.ldif" + +if test '!' -s "$DUMPFILE" -o "X$REFETCH" = Xyes; then + test -z "$DEBUG" || echo "$LDAP" 1>&2 + echo "Enter LDAP Password. The actual prompt is in the dump :)" 1>&2 + $LDAP | sed 's/ $//;/^Enter LDAP Password:/d' | tee "$DUMPFILE" | \ + grep "numEntries:" 1>&2 && echo "Success." 1>&2 || rm "$DUMPFILE" + test '!' -s "$DUMPFILE" && echo "Error loading dump." 1>&2 && exit 1 +fi + +test -z "$TO_STDOUT" && echo "$DUMPFILE" || cat "$DUMPFILE" + addfile ./clients/helpers/ldapquery hunk ./clients/helpers/ldapquery 1 +#!/bin/sh + +postprocess() { + test -z "$*" && cat && return + awk -F '::* ' 'BEGIN { fcount=split("'"$*"'", fields, " "); } + /^#/ { next; } + NF>=2 { obj[$1] = obj[$1] ? obj[$1] ";" $2 : $2; next; } + NF==0 { + if (! "dn" in obj) next; + line=obj[fields[1]]; + for(i = 2; i <= fcount; i++) + line = line "|" obj[fields[i]]; + if (line !~ /^\|*$/) print line; + delete obj; next; } + 1' +} + +LDAPCMD=ldapsearch +if test -n "$SSHPROXY"; then + LDAPCMD="ssh -t $SSHPROXY $LDAPCMD" +else + LDAPCMD="eval $LDAPCMD" +fi +test -z "$BINDURL" && echo "Define BINDURL in environment" 1>&2 && exit 1 +test -z "$BASEDN" && echo "Define BASEDN in environment" 1>&2 && exit 1 +test -n "$LDAPUSER" && BINDDN="uid=$LDAPUSER,ou=Users,$BASEDN" +test -z "$BINDDN" && echo "Define BINDDN in environment" 1>&2 && exit 1 +test -z "$SEARCHBASE" && SEARCHBASE="$BASEDN" +if test -z "$BINDPW"; then + PW="-W" +else + PW="-w$BINDPW" +fi +FILTER="$1"; shift +echo "$FILTER" | grep -q '=' || FILTER="cn=*$FILTER*" + +$LDAPCMD -x -H "'$BINDURL'" -D "'$BINDDN'" "'$PW'" -b "'$SEARCHBASE'" \ + "'($FILTER)'" "$@" \ + | perl -MMIME::Base64 -n -00 -e 's/\r//g;s/\n //g; + s/(?<=:: )(\S+)/quotemeta(decode_base64($1))/eg; + s/(\\[\n\r])+/\\\\n/g; + s/\\(.)/\1/g;print' \ + | postprocess "$@" + addfile ./clients/helpers/ldif-linify hunk ./clients/helpers/ldif-linify 1 +#!/bin/sh + +# put each paragraph from LDIF on one line for easier grepping etc. +# This script is used by ldif-normalise and test-directory.sh + +# 1. join continuation lines, normalise whitespace, remove comments, linify + +sed 's/ $//;$!{;/./{;H;d;};};$H;x;s/\n //g;s/ */ /g;s/\n#[^\n]*//g;s/\n/||/g' addfile ./clients/helpers/ldif-normalise hunk ./clients/helpers/ldif-normalise 1 +#!/bin/sh + +# This script modifies an LDIF so that if the content of the dumped data +# is the same, the LDIF should also be the same. Its primary use is to +# be able to use diff(1) on LDIF's without spurious changes. + +# to be used as a filter, e.g. ldapsearch ... | ldif-normalise | foo +LINIFY="`dirname $0`/ldif-linify" + +# 1. linify, remove non-objects, order entries by dn, unlinify +# 2-3. sort the attributes in each entry alphabetically, except dn at start +"$LINIFY" | grep '||dn::* ' | LC_ALL=C sort -f | sed 's/||/\n/g' | \ +sed 's/^dn::* /00&/' | awk '/^$/{n++};{printf "%05d %s\n", n, $0}' | \ +LC_ALL=C sort | cut -c7- | sed 's/^00\(dn::* \)/\1/' + addfile ./clients/helpers/ldifdiff.pl hunk ./clients/helpers/ldifdiff.pl 1 +#! /usr/bin/perl + +=head1 NAME + +ldifdiff.pl -- Generates LDIF change diff between two sorted LDIF files. + +=head1 DESCRIPTION + +ldifdiff.pl takes as input two sorted LDIF files, source and target, and +generates on standard output the LDIF changes needed to transform the target +into the source. + +=head1 SYNOPSIS + +ldifdiff.pl B<-k|--keyattr keyattr> [B<-a|--sourceattrs attr1,attr2,...>] [B<-c|--ciscmp attr1,...>] [B<-n|--numcmp attr1,...>] [B<--dnattrs attr1,...>] [B<--sharedattrs attr1,...>] B B + +=head1 OPTIONS + +=over 4 + +=item B<-k|--keyattr> keyattr + +Specifies the key attribute to use when comparing source and target entries. +Entries in both LDIF files must be sorted by this attribute for comparisons to +be meaningful. F can be used to sort LDIF files by a given +attribute. + +=item B<-a|--sourceattrs attr1,attr2,...> + +(Optional) Specifies a list of attributes to consider when comparing +source and target entries. By default, all attributes are considered. + +=item B<-c|--ciscmp attr1,...> + +(Optional) Compare values of the specified attributes case-insensitively. The +default set is: mail manager member objectclass owner uid uniqueMember + +=item B<-n|--numcmp attr1,...> + +(Optional) Compare values of the specified attributes numerically. The +default set is: employeeNumber + +=item B<--dnattrs attr1,...> + +(Optional) Specifies a list of attributes to be treated as DNs when being +compared. The default set is: manager member owner uniqueMember + +=item B<--sharedattrs attr1,...> + +(Optional) Specifies a list of attribues to be treated as "shared" attributes, +where the source may not be a sole authoritative source. When modifying +these attributes, separate "delete" and "add" LDIF changes are generated, +instead of a single "replace" change. The default set is objectClass. + +=item B + +Specifies the source LDIF file. + +=item B + +Specifies the target LDIF file. + +=back + +=cut + +use Net::LDAP; +use Net::LDAP::LDIF; +use Net::LDAP::Util qw(canonical_dn); +use Getopt::Long; + +use strict; + +my @sourceattrs; +my (%ciscmp, %numcmp, %dnattrs, %sharedattrs); +my $keyattr; +GetOptions('a|sourceattrs=s' => sub { @sourceattrs = split(/,/, $_[1]) }, + 'c|ciscmp=s' => sub { my @a = split(/,/,lc $_[1]); @ciscmp{@a} = (1) x @a }, + 'dnattrs=s' => sub { my @a = split(/,/,lc $_[1]); @dnattrs{@a} = (1) x @a }, + 'k|keyattr=s' => \$keyattr, + 'n|numcmp=s' => sub { my @a = split(/,/,lc $_[1]); @numcmp{@a} = (1) x @a }, + 'sharedattrs=s' => sub {my @a=split(/,/,lc $_[1]);@sharedattrs{@a}=(1) x @a} + ); +unless (keys %ciscmp) { + foreach (qw(mail manager member objectclass owner uid uniquemember)) + { $ciscmp{$_} = 1 } +} +unless (keys %numcmp) { + foreach (qw(employeenumber)) + { $numcmp{$_} = 1 } +} +unless (keys %dnattrs) { + foreach (qw(manager member owner uniquemember)) + { $dnattrs{$_} = 1 } +} +%sharedattrs = (objectclass => 1) + unless keys %sharedattrs; + + +my ($sourcefile, $targetfile); +$sourcefile = shift; $targetfile = shift; + +die "usage: $0 -k|--keyattr keyattr [-a|--sourceattrs attr1,attr2,...] [-c|--ciscmp attr1,...] [--dnattrs attr1,...] [--sharedattrs attr1,...] sourcefile targetfile\n" + unless $keyattr && $sourcefile && $targetfile; + +my $source = Net::LDAP::LDIF->new($sourcefile) + or die "Can't open LDIF file $sourcefile: $!\n"; + +my $target = Net::LDAP::LDIF->new($targetfile) + or die "Can't open LDIF file $targetfile: $!\n"; + +my $ldifout = Net::LDAP::LDIF->new('-', 'w'); +$ldifout->{change} = 1; +$ldifout->{wrap} = 78; + +diff($source, $target); +exit; + + +# Gets the relative distinguished name (RDN) attribute +sub rdnattr { ($_[0] =~ /^(.*?)=/)[0] } + +# Gets the relative distinguished name (RDN) value +sub rdnval { my $rv = ($_[0] =~ /=(.*)/)[0]; $rv =~ s/(? 'lower'); + my $cbdn = canonical_dn($bdn, casefold => 'lower'); + my $rdnattr = lc rdnattr($cadn); + if ($ciscmp{$rdnattr}) { $cadn = lc($cadn), $cbdn = lc($cbdn) } + + return $numcmp{$rdnattr} ? $cadn <=> $cbdn : $cadn cmp $cbdn; +} + +sub cmpEntries +{ + my ($a, $b) = @_; + my $dncmp = cmpDNs($a->dn, $b->dn); + + if (lc($keyattr) eq 'dn') { + return ($dncmp, $dncmp); + } + else { + my $aval = $a->get_value($keyattr); + my $bval = $b->get_value($keyattr); + if ($ciscmp{$keyattr}) { + $aval = lc($aval); + $bval = lc($bval); + } + return($numcmp{$keyattr} ? $aval <=> $bval : $aval cmp $bval, $dncmp); + } +} + + +# Diffs two LDIF data sources +sub diff +{ + my ($source, $target) = @_; + my ($sourceentry, $targetentry, $incr_source, $incr_target, @ldifchanges); + + $sourceentry = $source->read_entry(); + $targetentry = $target->read_entry(); + + while () { + # End of all data + last if !$sourceentry && !$targetentry; + + # End of source data, but more target data. Delete. + if (!$sourceentry && $targetentry) { + $targetentry->delete; + $ldifout->write_entry($targetentry); + $incr_target = 1, next; + } + + # End of target data, but more data in source. Add. + if ($sourceentry && !$targetentry) { + $ldifout->write_entry($sourceentry); + $incr_source = 1, next; + } + + my ($entrycmp, $dncmp) = cmpEntries($sourceentry, $targetentry); + + # Check if the current source entry has a higher sort position than + # the current target. If so, we interpret this to mean that the + # target entry no longer exists on the source. Issue a delete to LDAP. + if ($entrycmp > 0) { + $targetentry->delete; + $ldifout->write_entry($targetentry); + $incr_target = 1, next; + } + # Check if the current source entry has a lower sort position than + # the current target entry. If so, we interpret this to mean that the + # source entry doesn't exist on the target. Issue an add to LDAP. + elsif ($entrycmp < 0) { + $ldifout->write_entry($sourceentry); + $incr_source = 1, next; + } + + # When we get here, we're dealing with the same person in $sourceentry + # and $targetentry. Compare the data and generate the update. + + # If a mod{R}DN is necessary, it needs to happen before other mods + if ($dncmp) { + my $rdnattr = rdnattr($sourceentry->dn); + my $rdnval = rdnval($sourceentry->dn); + my $newsuperior = dnsuperior($sourceentry->dn); + my $oldsuperior = dnsuperior($targetentry->dn); + my $changetype; + + if (cmpDNs($oldsuperior, $newsuperior)) { + $changetype = 'moddn'; + $targetentry->add(newsuperior => $newsuperior); + } + else { $changetype = 'modrdn' } + $targetentry->{changetype} = $changetype; + $targetentry->add(newrdn => "$rdnattr=$rdnval", + deleteoldrdn => '1'); + $ldifout->write_entry($targetentry); + $targetentry->delete('newrdn'); + $targetentry->delete('deleteoldrdn'); + $targetentry->delete('newsuperior') if $changetype eq 'moddn'; + delete($targetentry->{changetype}); + + $targetentry->dn($sourceentry->dn); + $targetentry->replace($rdnattr, $sourceentry->get_value($rdnattr)) + if $sourceentry->exists($rdnattr); + } + + # Check for differences and generate LDIF as appropriate + updateFromEntry($sourceentry, $targetentry, @sourceattrs); + $ldifout->write_entry($targetentry) if @{$targetentry->{changes}}; + $incr_source = 1, $incr_target = 1, next; + + } continue { + if ($incr_source) { + $sourceentry = $source->read_entry(); $incr_source = 0; + } + if ($incr_target) { + $targetentry = $target->read_entry(); $incr_target = 0; + } + } +} + +# Generate LDIF to update $target with information in $source. +# Optionally restrict the set of attributes to consider. +sub updateFromEntry +{ + my ($source, $target, @attrs) = @_; + my ($attr, $val, $ldifstr); + + unless (@attrs) { + # add all source entry attributes + @attrs = $source->attributes; + # add any other attributes we haven't seen from the target entry + foreach my $tattr ($target->attributes) { + push(@attrs, $tattr) unless grep(/^$tattr$/i, @attrs) + } + } + + $target->{changetype} = 'modify'; + + foreach $attr (@attrs) { + my $lcattr = lc $attr; + next if $lcattr eq 'dn'; # Can't handle modrdn here + + # Build lists of unique values in the source and target, to + # speed up comparisons. + my @sourcevals = $source->get_value($attr); + my @targetvals = $target->get_value($attr); + my (%sourceuniqvals, %targetuniqvals); + foreach (@sourcevals) { + my ($origval, $val) = ($_, $_); + $val = lc $val if $ciscmp{$lcattr}; + # Get rid of spaces after non-escaped commas in DN attrs + $val =~ s/(?delete($attr => [ values(%targetuniqvals) ]) + if keys(%targetuniqvals); + $target->add($attr => [ values(%sourceuniqvals) ]) + if keys(%sourceuniqvals); + } + else { + # Issue a replace or delete as needed + if (@sourcevals) { $target->replace($attr => [ @sourcevals ]) } + else { $target->delete($attr) } + } + } + + # Get rid of the "changetype: modify" if there were no changes + delete($target->{changetype}) unless @{$target->{changes}}; +} + + +=back + +=head1 AUTHOR + +Kartik Subbarao Esubbarao@computer.orgE + +=cut + addfile ./clients/helpers/ldifsort.pl hunk ./clients/helpers/ldifsort.pl 1 +#! /usr/bin/perl +# $Id: ldifsort.pl,v 1.9 2005/04/03 20:20:24 subbarao Exp $ + +=head1 NAME + +ldifsort.pl - Sorts an LDIF file by the specified key attribute. The sorted +version is written to standard output. + +=head1 DESCRIPTION + +Sorts an LDIF file by the specified key attribute. + +=head1 SYNOPSIS + +ldifsort.pl B<-k keyattr> [B<-andc>] file.ldif + +=over 4 + +=item B<-k> + +Specifies the key attribute for making sort comparisons. If 'dn' is +specified, sorting is done by the full DN string, which can be composed of +different attributes for different entries. + +=item B<-a> + +Specifies that attributes within a given entry should also be sorted. This +has the side effect of removing all comments and line continuations in the +LDIF file. + +=item B<-n> + +Specifies numeric comparisons on the key attribute. Otherwise string +comparisons are done. + +=item B<-d> + +Specifies that the key attribute is a DN. Comparisons are done on a +DN-normalized version of attribute values. This is the default +behavior if 'dn' is passed as the argument to B<-k>. + +=item B<-c> + +Specifies case-insensitive comparisons on the key attribute. This is the +default behavior if 'dn' is passed as the argument to B<-k>. + +=back + + +=head1 AUTHOR + +Kartik Subbarao Esubbarao@computer.orgE + +=cut + + +use Net::LDAP::Util qw(canonical_dn); +use MIME::Base64; +use Getopt::Std; + +use strict; + +my %args; +getopts("k:andc", \%args); + +my $keyattr = $args{k}; +my $sortattrs = $args{a}; +my $ciscmp = $args{c}; +my $ldiffile = $ARGV[0]; + +die "usage: $0 -k keyattr [-n] [-d] [-c] ldiffile\n" + unless $keyattr && $ldiffile; + +$/ = ""; + +open(LDIFH, $ldiffile) || die "$ldiffile: $!\n"; + +my $pos = 0; +my @valuepos; +while () { + my $value; + 1 while s/^($keyattr:.*)?\n /$1/im; # Handle line continuations + if (/^$keyattr(::?) (.*)$/im) { + $value = $2; + $value = decode_base64($value) if $1 eq '::'; + } + $value = lc($value) if $ciscmp; + push @valuepos, [ $value, $pos ]; + $pos = tell; +} + +sub cmpattr { $a->[0] cmp $b->[0] } +sub cmpattrnum { $a->[0] <=> $b->[0] } +my %canonicaldns; +sub cmpdn { + my $cadn = ($canonicaldns{$a->[0]} ||= lc(canonical_dn($a->[0]))); + my $cbdn = ($canonicaldns{$b->[0]} ||= lc(canonical_dn($b->[0]))); + $cadn cmp $cbdn; +} + +my $cmpfunc; +if ($args{d} || lc($keyattr) eq 'dn') { $cmpfunc = \&cmpdn } +elsif ($args{n}) { $cmpfunc = \&cmpattrnum } +else { $cmpfunc = \&cmpattr; } + +my @sorted; +@sorted = sort $cmpfunc @valuepos; + +foreach my $valuepos (@sorted) { + seek(LDIFH, $valuepos->[1], 0); + my $entry = ; + if ($sortattrs) { + $entry =~ s/\n //mg; # collapse line continuations + my @lines = grep(!/^#/, split(/\n/, $entry)); + my $dn = shift(@lines); + print "$dn\n", join("\n", sort @lines), "\n\n"; + } + else { + print $entry; + print "\n" if $entry !~ /\n\n$/; + } +}