From 0e8fd3398771da2f016d72830179507f3edda51b Mon Sep 17 00:00:00 2001 From: Samba Release Account Date: Sat, 4 May 1996 07:50:46 +0000 Subject: Initial version imported to CVS (This used to be commit 291551d80711daab7b7581720bcd9a08d6096517) --- examples/misc/extra_smbstatus | 47 +++++++++++++++++++++++++++++++++++++++++++ examples/misc/wall.perl | 45 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 examples/misc/extra_smbstatus create mode 100644 examples/misc/wall.perl (limited to 'examples/misc') diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus new file mode 100644 index 0000000000..b018f3dcce --- /dev/null +++ b/examples/misc/extra_smbstatus @@ -0,0 +1,47 @@ +Here's something that Paul Blackman sent me that may be useful: + +------------------- +I created this script to do a few things that smbstatus doesn't at the +moment. Perhaps you might want to include these. Sorry I haven't +added things at source level, script was quick&easy. + +******* +#!/bin/csh +if ($1 == "-p") then + smbstatus -p |sort -u +else if ($1 == "-c") then + echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique +smbd processes running. + else if ($1 == "-l") then + echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z +|grep -c :` >>$2 +else + smbstatus |sort +3 -4 -u +endif +****** + +The '-p' option was just to show unique PIDs. + +The more important ones are the '-c' and '-l' options '-c' just counts +the number of unique smbd's, While '-l' logs this count with date and +time to a log file specified on the command line. I'm using '-l' at +the moment with cron to give me an idea of usage/max connections etc. +I was also thinking of doing a log for individual/specified services. + +The default (last) option was to show unique PIDs with user names. +Unfortunately this still lists all file locks etc. This would be +better with a 'no locked files' option from smbstatus (or is there one +that I didn't see) + +Cheers, +~^ MIME OK ^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~ + o | Paul Blackman ictinus@lake.canberra.edu.au + o | Co-operative Research ------------------------ + o _ | Centre For Freshwater Ecology. Ph. (Aus) 06 2012518 + -- (") o | University of Canberra, Australia. Fax. " 06 2015038 + \_|_-- |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | "Spend a little love and get high" + _/ \_ | - Lenny Kravitz +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~ SAMBA Web Pages: http://samba.canberra.edu.au/pub/samba/samba.html ~~~~~ + diff --git a/examples/misc/wall.perl b/examples/misc/wall.perl new file mode 100644 index 0000000000..fc3dc2e2c0 --- /dev/null +++ b/examples/misc/wall.perl @@ -0,0 +1,45 @@ +#!/usr/local/bin/perl +# +#@(#) smb-wall.pl Description: +#@(#) A perl script which allows you to announce whatever you choose to +#@(#) every PC client currently connected to a Samba Server... +#@(#) ...using "smbclient -M" message to winpopup service. +#@(#) Default usage is to message every connected PC. +#@(#) Alternate usage is to message every pc on the argument list. +#@(#) Hacked up by Keith Farrar +# +#============================================================================= +$smbstatus = "/usr/local/bin/smbstatus"; +$smbclient = "/usr/local/bin/smbclient"; + +print STDOUT "\nEnter message for Samba clients of this host\n"; +print STDOUT "(terminated with single '.' or end of file):\n"; + +while ( ) { + /^\.$/ && last; + push(@message, $_); +} + +if ( $ARGV[0] ne "" ) { + $debug && print STDOUT "Was given args: \n\t @ARGV\n"; + foreach $client ( @ARGV ) { + $pcclient{$client} = $client; + } +} else { + open( PCLIST, "$smbstatus | /bin/awk '/^[a-z]/ {print $5}' | /bin/sort | /bin/uniq|"); + while ( ) { + /^[a-z]+[a-z0-9A-Z-_]+.+/ || next; + ($share, $user, $group, $pid, $client, @junk) = split; + $pcclient{$client} = $client; + } + close(PCLIST); +} + +foreach $pc ( keys(%pcclient) ) { + print STDOUT "Sending message "; + $debug && print STDOUT " <@message> \n"; + print STDOUT "To <$pc>\n"; + open(SENDMSG,"|$smbclient -M $pc") || next; + print SENDMSG @message; + close(SENDMSG); +} -- cgit From 5c909179e8fbf4c57c88b9699756578c4aa92e29 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 4 May 1996 10:51:22 +0000 Subject: updates to wall.perl from michal@ellpspace.math.ualberta.ca (This used to be commit 30909756b16b2c78769a976809046af0b6a98b6e) --- examples/misc/wall.perl | 76 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 26 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/wall.perl b/examples/misc/wall.perl index fc3dc2e2c0..9303658ce1 100644 --- a/examples/misc/wall.perl +++ b/examples/misc/wall.perl @@ -6,40 +6,64 @@ #@(#) ...using "smbclient -M" message to winpopup service. #@(#) Default usage is to message every connected PC. #@(#) Alternate usage is to message every pc on the argument list. -#@(#) Hacked up by Keith Farrar +#@(#) Hacked up by Keith Farrar # +# Cleanup and corrections by +# Michal Jaegermann +# Message to send can be now also fed (quietly) from stdin; a pipe will do. #============================================================================= -$smbstatus = "/usr/local/bin/smbstatus"; -$smbclient = "/usr/local/bin/smbclient"; -print STDOUT "\nEnter message for Samba clients of this host\n"; -print STDOUT "(terminated with single '.' or end of file):\n"; +$smbstatus = "/usr/local/bin/smbstatus"; +$smbshout = "/usr/local/bin/smbclient -M"; -while ( ) { - /^\.$/ && last; - push(@message, $_); +if (@ARGV) { + @clients = @ARGV; + undef @ARGV; } +else { # no clients specified explicitly + open(PCLIST, "$smbstatus |") || die "$smbstatus failed!.\n$!\n"; + while() { + last if /^Locked files:/; + split(' ', $_, 6); + # do not accept this line if less then six fields + next unless $_[5]; + # if you have A LOT of clients you may speed things up by + # checking pid - no need to look further if this pid was already + # seen; left as an exercise :-) + $client = $_[4]; + next unless $client =~ /^\w+\./; # expect 'dot' in a client name + next if grep($_ eq $client, @clients); # we want this name once + push(@clients, $client); + } + close(PCLIST); +} + +if (-t) { + print <<'EOT'; -if ( $ARGV[0] ne "" ) { - $debug && print STDOUT "Was given args: \n\t @ARGV\n"; - foreach $client ( @ARGV ) { - $pcclient{$client} = $client; - } -} else { - open( PCLIST, "$smbstatus | /bin/awk '/^[a-z]/ {print $5}' | /bin/sort | /bin/uniq|"); - while ( ) { - /^[a-z]+[a-z0-9A-Z-_]+.+/ || next; - ($share, $user, $group, $pid, $client, @junk) = split; - $pcclient{$client} = $client; - } - close(PCLIST); +Enter message for Samba clients of this host +(terminated with single '.' or end of file): +EOT + + while (<>) { + last if /^\.$/; + push(@message, $_); + } +} +else { # keep quiet and read message from stdin + @message = <>; } -foreach $pc ( keys(%pcclient) ) { - print STDOUT "Sending message "; - $debug && print STDOUT " <@message> \n"; - print STDOUT "To <$pc>\n"; - open(SENDMSG,"|$smbclient -M $pc") || next; +foreach(@clients) { +## print "To $_:\n"; + if (open(SENDMSG,"|$smbshout $_")) { print SENDMSG @message; close(SENDMSG); + } + else { + warn "Cannot notify $_ with $smbshout:\n$!\n"; + } } + +exit 0; + -- cgit From 0b13d2e55d8fda8d7b173dd2d2495f3d24275fe6 Mon Sep 17 00:00:00 2001 From: Samba Release Account Date: Mon, 6 May 1996 06:47:02 +0000 Subject: Updated smbstat script with a better one, Paul. (This used to be commit c26a534541b96f939daaf9b35f805db2594783ca) --- examples/misc/extra_smbstatus | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus index b018f3dcce..363e7f67af 100644 --- a/examples/misc/extra_smbstatus +++ b/examples/misc/extra_smbstatus @@ -10,28 +10,31 @@ added things at source level, script was quick&easy. if ($1 == "-p") then smbstatus -p |sort -u else if ($1 == "-c") then - echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique -smbd processes running. + echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique smbd processes running. else if ($1 == "-l") then - echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z -|grep -c :` >>$2 + echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z |grep -c :` >>$2 +else if ($1 == "-cs") then + echo There are `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` concurrent connections to share: $2 +else if ($1 == "-csl") then + echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` >>$3 else - smbstatus |sort +3 -4 -u + echo "'smbstat -c' ==> Count unique smbd processes." + echo "'smbstat -p' ==> List unique smbd processes." + echo "'smbstat -l logfile' ==> Append a log entry for the number of" + echo " concurrent and unique processes to logfile." + echo "'smbstat -cs sharename'" + echo " ==> Count processes connected to sharename (assumed unique)" + echo "'smbstat -csl sharename logfile'" + echo " ==> Append a log entry for the number of concurrent" + echo " processes connected to sharename (assumed unique)" endif ****** -The '-p' option was just to show unique PIDs. +Run this script from cron eg. -The more important ones are the '-c' and '-l' options '-c' just counts -the number of unique smbd's, While '-l' logs this count with date and -time to a log file specified on the command line. I'm using '-l' at -the moment with cron to give me an idea of usage/max connections etc. -I was also thinking of doing a log for individual/specified services. +0,5,10,15,20,25,30,35,40,50,55 * * * * /usr/local/samba/bin/smbstat -l /usr/local/samba/var/smbdcount.log -The default (last) option was to show unique PIDs with user names. -Unfortunately this still lists all file locks etc. This would be -better with a 'no locked files' option from smbstatus (or is there one -that I didn't see) +and you get a good idea of usage over time. Cheers, ~^ MIME OK ^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~ -- cgit From 754c280835d516f3d6d78872f6eaecc70c10af43 Mon Sep 17 00:00:00 2001 From: Samba Release Account Date: Tue, 7 Oct 1997 04:56:02 +0000 Subject: More references to samba.canberra Mental note: always commit from root directory. :^o Paul. (This used to be commit 5a38eaac75a6bede2d946f69cf664d7ca3989b55) --- examples/misc/extra_smbstatus | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/misc') diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus index 363e7f67af..584284feb3 100644 --- a/examples/misc/extra_smbstatus +++ b/examples/misc/extra_smbstatus @@ -46,5 +46,5 @@ Cheers, | | "Spend a little love and get high" _/ \_ | - Lenny Kravitz ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~ SAMBA Web Pages: http://samba.canberra.edu.au/pub/samba/samba.html ~~~~~ +~~~~~~~~~~~~~~ SAMBA Web Pages: http://samba.anu.edu.au/samba/ ~~~~~~~~~~~~~~ -- cgit From f120a81a727efbb6c264b90df3c7b78ab554a428 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 21 Nov 1998 13:20:31 +0000 Subject: global change from samba.anu.edu.au to samba.org (This used to be commit 42d2509c9fab5c774fd33b9d4b5bd1ee125479c3) --- examples/misc/extra_smbstatus | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/misc') diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus index 584284feb3..7f77d07d00 100644 --- a/examples/misc/extra_smbstatus +++ b/examples/misc/extra_smbstatus @@ -46,5 +46,5 @@ Cheers, | | "Spend a little love and get high" _/ \_ | - Lenny Kravitz ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~ SAMBA Web Pages: http://samba.anu.edu.au/samba/ ~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~ SAMBA Web Pages: http://samba.org/samba/ ~~~~~~~~~~~~~~ -- cgit From 87591d8ab55b0e3204c4877f55189eb6755ce16a Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Mon, 28 Aug 2000 13:35:10 +0000 Subject: script written by herb for reporting which smb.conf parameters are in loarparm.c but not supported by SWAT. I just thought it looked fun. :-) --jerry (This used to be commit eb20a2c6f478688b82ce8346fea618aebbfc9295) --- examples/misc/swat.pl | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 examples/misc/swat.pl (limited to 'examples/misc') diff --git a/examples/misc/swat.pl b/examples/misc/swat.pl new file mode 100644 index 0000000000..f43aea029a --- /dev/null +++ b/examples/misc/swat.pl @@ -0,0 +1,96 @@ +#! /usr/bin/perl5 +## +## This is a simple script written by Herb Lewis @ SGI +## for reporting which parameters where supported by loadparm.c but +## not by SWAT I just thought it looked fun and might be of interest to others +## --jerry@samba.org +## + +$lastone = "nothing"; + +if (@ARGV[0]) { + $filename = @ARGV[0]; +} else { + $filename = "/usr3/samba20/samba/source/param/loadparm.c"; +} + +open (INFILE,$filename) || die "unable to open $filename\n"; +while (not eof(INFILE)) +{ + $_ = ; + last if ( /^static struct parm_struct parm_table/) ; +} +print "Option Name Global Page Share Page Printer Page\n"; +print "---------------------------------------------------------------------"; +while (not eof(INFILE)) +{ + $_ = ; + last if (/};/); + @fields = split(/,/,$_); + next if not ($fields[0] =~ /^.*{"/); + $fields[0] =~ s/.*{"//; + $fields[0] =~ s/"//; + if ($fields[3] eq $lastone) { + print " $fields[0]\n"; + next; + } + $lastone = $fields[3]; + $fields[2] =~ s/^\s+//; + $fields[2] =~ s/\s+$//; + $fields[2] =~ s/}.*$//; + $fields[6] =~ s/^\s+//; + $fields[6] =~ s/\s+$//; + $fields[6] =~ s/}.*$//; + if ($fields[2] =~ /P_SEPARATOR/) { + print "\n****************$fields[0]\n"; + next; + } + else { + if ($fields[6] =~ /FLAG_DEPRECATED/) { + print "*$fields[0]".' 'x(31-length($fields[0])); + } + else { + print "$fields[0]".' 'x(32-length($fields[0])); + } + } + if (($fields[2] =~ /P_GLOBAL/) || ($fields[6] =~ /FLAG_GLOBAL/)) { + if ($fields[6] =~ /FLAG_GLOBAL/) { + print "*"; + } + else { + print " "; + } + if ($fields[6] =~ /FLAG_BASIC/) { + print "BASIC "; + } + else { + print "ADVANCED "; + } + } + else { + print " no "; + } + if ($fields[6] =~ /FLAG_SHARE/) { + if ($fields[6] =~ /FLAG_BASIC/) { + print "BASIC "; + } + else { + print "ADVANCED "; + } + } + else { + print "no "; + } + if ($fields[6] =~ /FLAG_PRINT/) { + if ($fields[6] =~ /FLAG_BASIC/) { + print "BASIC"; + } + else { + print "ADVANCED"; + } + } + else { + print "no"; + } + print "\n"; +} -- cgit From 0c5bbb3bbdaa634361d2abbc4d705343df448caa Mon Sep 17 00:00:00 2001 From: Herb Lewis Date: Mon, 28 Aug 2000 18:58:46 +0000 Subject: added a little description of useage and output format since this gives more info than just what parameters are not supported by SWAT. (This used to be commit 7db533cb47a0d9bc88219dbe48e96ceed45a65a1) --- examples/misc/swat.pl | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'examples/misc') diff --git a/examples/misc/swat.pl b/examples/misc/swat.pl index f43aea029a..f6414b6349 100644 --- a/examples/misc/swat.pl +++ b/examples/misc/swat.pl @@ -1,10 +1,36 @@ #! /usr/bin/perl5 ## ## This is a simple script written by Herb Lewis @ SGI -## for reporting which parameters where supported by loadparm.c but +## for reporting which parameters are supported by loadparm.c but ## not by SWAT I just thought it looked fun and might be of interest to others ## --jerry@samba.org ## +## Here is a little info on the usage and output format so you don't have +## to dig through the code to understand what is printed. +## +## Useage: swat.pl [path_to_loadparm.c] +## +## The output consists of 4 columns of information +## Option Name, Global Page, Share Page, Printer Page +## The section separaters will also be printed (preceded by 16 *) to show +## which options are grouped in the various sections. +## +## If the option name is preceded by an * it means this is a deprecated option. +## If the option name is preceded by 5 spaces it means this is an alias for the +## previous option. +## +## Under the Global Page, Share Page, and Printer Page columns there will be +## one of 3 entries, BASIC, ADVANCED, or no. "BASIC" indicates this option will +## show in the Basic View of that page in SWAT. "ADVANCED" indicates this +## option will show in the Advanced View of that page in SWAT. "No" indicates +## that this option is not available on that page in SWAT. +## +## Under the Global Page column, if an entry begins with an * it indicates that +## this is actually specified in Samba as a "service parameter" not a "global +## parameter" but you can set a default value for this on the Global Page in +## SWAT. +## +## --herb@samba.org $lastone = "nothing"; -- cgit From c4d68a29c97ba14a9df6dbcc73d0edc6f21bd0f4 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 31 Jul 2002 14:56:40 +0000 Subject: merge from SAMBA_2_2 (This used to be commit 72d36c9b2596cda6c3c25c18ddb4c58d55519ff8) --- examples/misc/modify_samba_config.pl | 154 +++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100755 examples/misc/modify_samba_config.pl (limited to 'examples/misc') diff --git a/examples/misc/modify_samba_config.pl b/examples/misc/modify_samba_config.pl new file mode 100755 index 0000000000..eb997f9b0c --- /dev/null +++ b/examples/misc/modify_samba_config.pl @@ -0,0 +1,154 @@ +#!/usr/bin/perl + +## +## Simple example of how to implement a '[add|delete] share command' for +## use with the Windows NT Server Manager. See smb.conf(5) for details +## on the '[add|delete] share command' +## +## Author : Gerald (Jerry) Carter +## + +use POSIX qw(tmpnam); + +## +## local variables +## +my $delete_mode = undef; +my $add_mode = undef; +my $tmp_file_name = undef; + + +## check for correct parameters +if ($#ARGV == 1) { + $delete_mode = 1; +} +elsif ($#ARGV == 3) { + $add_mode = 1; +} +else { + print "Usage: $0 configfile share [path] [comment]\n"; + exit -1; +} + +## first param is always the config file +open (CONFIGFILE, "$ARGV[0]") || die "Unable to open $ARGV[0] for reading!\n"; + +## FIXME!! Right now we throw away all comments in the file. +while () { + + chomp($_); + + ## eat leading whitespace + $_ =~ s/^\s*//; + + ## eat trailing whitespace + $_ =~ s/\s*$//; + + + ## throw away comments + next if (($_ =~ /^#/) || ($_ =~ /^;/)); + + ## set the current section name for storing the hash + if ($_ =~ /^\[.*\]$/) { + + $_ = substr($_, 1, length($_)-2); + + if ( length($_) ) { + $section = $_; + } + else { + print "Bad Section Name - no closing ]\n"; + exit -1; + } + + next; + } + + ## check for a param = value + if ($_ =~ /=/) { + ($param, $value) = split (/=/, $_); + $param =~ s/./\l$&/g; + $param =~ s/\s+//g; + $value =~ s/^\s+//; + + $config{$section}{$param} = $value; + + next; + } + + ## should have a hash of hashes indexed by section name +} +close (CONFIGFILE); + +## +## We have the smb.conf in our hash of hashes now. +## Add or delete +## +if ($add_mode) { + $config{$ARGV[1]}{'path'} = $ARGV[2]; + $config{$ARGV[1]}{'comment'} = $ARGV[3]; +} +elsif ($delete_mode) { + delete $config{$ARGV[1]}; +} + +## +## Print the resulting configuration +## +#do { +# $tmp_file_name = tmpnam(); +# print "Using temporary file - $tmp_file_name\n"; +#} while (!sysopen(TMP, $tmp_file_name, O_RDWR|O_CREAT|O_EXCL)); +$tmp_file_name = tmpnam(); +open (TMP, ">$tmp_file_name") || die "Unable to open temporary file for writing!\n"; + +PrintConfigFile(TMP); + +## now overwrite the original config file +close (TMP); +system ("cp -pf $ARGV[0] $ARGV[0].bak"); +system ("cp -pf $tmp_file_name $ARGV[0]"); +unlink $tmp_file_name; + + +exit 0; + + + + + +####################################################################################### +## PrintConfigFile() +## +sub PrintConfigFile { + my ($output) = @_; + + ## print the file back out, beginning with the global section + print $output "#\n# Generated by $0\n#\n"; + + PrintSection ($output, 'global', $config{'global'}); + + foreach $section (keys %config) { + + if ("$section" ne "global") { + print $output "## Section - [$section]\n"; + PrintSection ($output, $section, $config{$section}); + } + } + + print $output "#\n# end of generated smb.conf\n#\n"; +} + +####################################################################################### +## PrintSection() +## +sub PrintSection { + my ($outfile, $name, $section) = @_; + + print $outfile "[$name]\n"; + foreach $param (keys %$section) { + print $outfile "\t$param".' 'x(25-length($param)). " = $$section{$param}\n"; + } + print $outfile "\n"; + +} -- cgit From 9d97b204731b515204895a499290eb32a641d823 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 14 Dec 2003 17:47:15 +0000 Subject: When parsing 'param = value', don't split 'value' at spaces. Thanks to Ralf Spenneberg for the fix. Volker (This used to be commit bc383582b248518e39225405d0def411d552aa7d) --- examples/misc/modify_samba_config.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/misc') diff --git a/examples/misc/modify_samba_config.pl b/examples/misc/modify_samba_config.pl index eb997f9b0c..ad958625d6 100755 --- a/examples/misc/modify_samba_config.pl +++ b/examples/misc/modify_samba_config.pl @@ -66,7 +66,7 @@ while () { ## check for a param = value if ($_ =~ /=/) { - ($param, $value) = split (/=/, $_); + ($param, $value) = split (/=/, $_,2); $param =~ s/./\l$&/g; $param =~ s/\s+//g; $value =~ s/^\s+//; -- cgit From 704862b6870bc72dd6d7bf64d2d3788101b39de1 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 19 Jan 2005 20:44:00 +0000 Subject: r4855: add some smb.conf script for add/delete/change share and addprinter hooks (This used to be commit 073592b7ad539138763c457fe58c1d82b2daa9c1) --- examples/misc/modify_samba_config.pl | 154 ----------------------------------- 1 file changed, 154 deletions(-) delete mode 100755 examples/misc/modify_samba_config.pl (limited to 'examples/misc') diff --git a/examples/misc/modify_samba_config.pl b/examples/misc/modify_samba_config.pl deleted file mode 100755 index ad958625d6..0000000000 --- a/examples/misc/modify_samba_config.pl +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/perl - -## -## Simple example of how to implement a '[add|delete] share command' for -## use with the Windows NT Server Manager. See smb.conf(5) for details -## on the '[add|delete] share command' -## -## Author : Gerald (Jerry) Carter -## - -use POSIX qw(tmpnam); - -## -## local variables -## -my $delete_mode = undef; -my $add_mode = undef; -my $tmp_file_name = undef; - - -## check for correct parameters -if ($#ARGV == 1) { - $delete_mode = 1; -} -elsif ($#ARGV == 3) { - $add_mode = 1; -} -else { - print "Usage: $0 configfile share [path] [comment]\n"; - exit -1; -} - -## first param is always the config file -open (CONFIGFILE, "$ARGV[0]") || die "Unable to open $ARGV[0] for reading!\n"; - -## FIXME!! Right now we throw away all comments in the file. -while () { - - chomp($_); - - ## eat leading whitespace - $_ =~ s/^\s*//; - - ## eat trailing whitespace - $_ =~ s/\s*$//; - - - ## throw away comments - next if (($_ =~ /^#/) || ($_ =~ /^;/)); - - ## set the current section name for storing the hash - if ($_ =~ /^\[.*\]$/) { - - $_ = substr($_, 1, length($_)-2); - - if ( length($_) ) { - $section = $_; - } - else { - print "Bad Section Name - no closing ]\n"; - exit -1; - } - - next; - } - - ## check for a param = value - if ($_ =~ /=/) { - ($param, $value) = split (/=/, $_,2); - $param =~ s/./\l$&/g; - $param =~ s/\s+//g; - $value =~ s/^\s+//; - - $config{$section}{$param} = $value; - - next; - } - - ## should have a hash of hashes indexed by section name -} -close (CONFIGFILE); - -## -## We have the smb.conf in our hash of hashes now. -## Add or delete -## -if ($add_mode) { - $config{$ARGV[1]}{'path'} = $ARGV[2]; - $config{$ARGV[1]}{'comment'} = $ARGV[3]; -} -elsif ($delete_mode) { - delete $config{$ARGV[1]}; -} - -## -## Print the resulting configuration -## -#do { -# $tmp_file_name = tmpnam(); -# print "Using temporary file - $tmp_file_name\n"; -#} while (!sysopen(TMP, $tmp_file_name, O_RDWR|O_CREAT|O_EXCL)); -$tmp_file_name = tmpnam(); -open (TMP, ">$tmp_file_name") || die "Unable to open temporary file for writing!\n"; - -PrintConfigFile(TMP); - -## now overwrite the original config file -close (TMP); -system ("cp -pf $ARGV[0] $ARGV[0].bak"); -system ("cp -pf $tmp_file_name $ARGV[0]"); -unlink $tmp_file_name; - - -exit 0; - - - - - -####################################################################################### -## PrintConfigFile() -## -sub PrintConfigFile { - my ($output) = @_; - - ## print the file back out, beginning with the global section - print $output "#\n# Generated by $0\n#\n"; - - PrintSection ($output, 'global', $config{'global'}); - - foreach $section (keys %config) { - - if ("$section" ne "global") { - print $output "## Section - [$section]\n"; - PrintSection ($output, $section, $config{$section}); - } - } - - print $output "#\n# end of generated smb.conf\n#\n"; -} - -####################################################################################### -## PrintSection() -## -sub PrintSection { - my ($outfile, $name, $section) = @_; - - print $outfile "[$name]\n"; - foreach $param (keys %$section) { - print $outfile "\t$param".' 'x(25-length($param)). " = $$section{$param}\n"; - } - print $outfile "\n"; - -} -- cgit From 9bdf6cdbf1d158ae37cd2c079a217c4011af212c Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Fri, 18 Feb 2005 16:43:20 +0000 Subject: r5444: Add adssearch.pl utility (on volkers request). Added to samba3 due to some header and machine-account dependencies, although it's possibly of more interest to samba4 developers. adssearch.pl is a kind of ldapsearch + dump-filters for various ADS-attributes. It can also register asynchronous change notifications. ./adssearch.pl -h w2k3host -D administrator@MY.REALM.NET -x -w mypass -n and *any* change in your entire DIT will show up immediately (after a second change of an object even as object diff). It's very interesting to see the interaction of GPOs, the various steps of account modification with dsa.msc, etc. Gracefully ignore some parts of adssearch.pl that are rather immature... Guenther (This used to be commit fd947b5ee060a48597bc1166614a05f81457e5e0) --- examples/misc/adssearch.pl | 1492 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1492 insertions(+) create mode 100755 examples/misc/adssearch.pl (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl new file mode 100755 index 0000000000..9bfc9e8a05 --- /dev/null +++ b/examples/misc/adssearch.pl @@ -0,0 +1,1492 @@ +#!/usr/bin/perl -w +# +# adssearch.pl - query an Active Directory server and +# display objects in a human readable format +# +# Copyright (C) Guenther Deschner 2003-2005 +# +# TODO: add range retrieval +# write sddl-converter, decode userParameters +# chase referrals +# apparently only win2k3 allows simple-binds with machine-accounts. +# make sasl support independent from Authen::SASL::Cyrus v >0.11 +use strict; + +use Net::LDAP; +use Net::LDAP::Control; +use Convert::ASN1; +use Time::Local; +use POSIX qw(strftime); +use Getopt::Long; + +my $have_sasl; +my $works_sasl; +my $pref_version; +BEGIN { + my $class = 'Authen::SASL'; + $pref_version = "0.32"; + if ( eval "require $class;" ) { + $have_sasl = 1; + } + if ( eval "Net::LDAP->VERSION($pref_version);" ) { + $works_sasl = 1; + } +} + +# users may set defaults here +my $base = ""; +my $binddn = ""; +my $password = ""; +my $server = ""; + +my $tdbdump = "/usr/bin/tdbdump"; +my $testparm = "/usr/bin/testparm"; +my $net = "/usr/bin/net"; +my $dig = "/usr/bin/dig"; +my $nmblookup = "/usr/bin/nmblookup"; +my $secrets_tdb = "/etc/samba/secrets.tdb"; +my $klist = "/usr/bin/klist"; +my $kinit = "/usr/bin/kinit"; +my $ads_h = "/home/gd/ads.h"; +my $page_size = "1000"; +my $workgroup = ""; +my $machine = ""; +my $realm = ""; + +# parse input +my ( + $opt_base, + $opt_binddn, + $opt_debug, + $opt_display_extendeddn, + $opt_display_metadata, + $opt_display_raw, + $opt_dump_rootdse, + $opt_dump_schema, + $opt_dump_wknguid, + $opt_help, + $opt_host, + $opt_machine, + $opt_notify, + $opt_notify_nodiffs, + $opt_password, + $opt_port, + $opt_realm, + $opt_saslmech, + $opt_scope, + $opt_simpleauth, + $opt_starttls, + $opt_user, + $opt_workgroup, +); + +GetOptions( + 'base|b=s' => \$opt_base, + 'D|DN=s' => \$opt_binddn, + 'debug=i' => \$opt_debug, + 'extendeddn|e' => \$opt_display_extendeddn, + 'help' => \$opt_help, + 'host|h=s' => \$opt_host, + 'machine|P' => \$opt_machine, + 'metadata|m' => \$opt_display_metadata, + 'nodiffs' => \$opt_notify_nodiffs, + 'notify|n' => \$opt_notify, + 'password|w=s' => \$opt_password, + 'port=i' => \$opt_port, + 'rawdisplay' => \$opt_display_raw, + 'realm|R=s' => \$opt_realm, + 'rootDSE' => \$opt_dump_rootdse, + 'saslmech|Y=s' => \$opt_saslmech, + 'schema|c' => \$opt_dump_schema, + 'scope|s=s' => \$opt_scope, + 'simpleauth|x' => \$opt_simpleauth, + 'tls|Z' => \$opt_starttls, + 'user|U=s' => \$opt_user, + 'wknguid' => \$opt_dump_wknguid, + 'workgroup|k=s' => \$opt_workgroup, + ); + + +# activate controls +my $paging = 1 if !$opt_notify; + +if (!@ARGV && !$opt_dump_schema && !$opt_dump_rootdse && !$opt_notify || $opt_help) { + usage(); + exit 1; +} + +# get the query +my $query = shift; +my @attrs = @ARGV; + +# some global vars +my ($filter, $dse, $uri); +my ($attr, $value); +my (@ctrls, @ctrls_s); +my ($ctl_paged, $cookie); +my ($page_count, $total_entry_count); +my ($sasl_hd, $async_ldap_hd, $sync_ldap_hd); +my ($mesg, $usn); +my (%entry_store); +my $async_search; +my (%ads_atype, %ads_gtype, %ads_uf); + +# fixed values and vars +my $set = "X"; +my $unset = "-"; + +# get defaults +my $scope = $opt_scope || "sub"; +my $port = $opt_port; + +my %ads_controls = ( +"LDAP_SERVER_NOTIFICATION_OID" => "1.2.840.113556.1.4.528", +"LDAP_SERVER_EXTENDED_DN_OID" => "1.2.840.113556.1.4.529", +"LDAP_PAGED_RESULT_OID_STRING" => "1.2.840.113556.1.4.319", +"LDAP_SERVER_SD_FLAGS_OID" => "1.2.840.113556.1.4.801", +"LDAP_SERVER_SORT_OID" => "1.2.840.113556.1.4.473", +"LDAP_SERVER_RESP_SORT_OID" => "1.2.840.113556.1.4.474", +"LDAP_CONTROL_VLVREQUEST" => "2.16.840.1.113730.3.4.9", +"LDAP_CONTROL_VLVRESPONSE" => "2.16.840.1.113730.3.4.10", +"LDAP_SERVER_RANGE_RETRIEVAL" => "1.2.840.113556.1.4.802", #unsure +"LDAP_SERVER_SHOW_DELETED_OID" => "1.2.840.113556.1.4.417", +"LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID" => "1.2.840.113556.1.4.521", +"LDAP_SERVER_LAZY_COMMIT_OID" => "1.2.840.113556.1.4.619", +"LDAP_SERVER_TREE_DELETE_OID" => "1.2.840.113556.1.4.805", +"LDAP_SERVER_DIRSYNC_OID" => "1.2.840.113556.1.4.841", +"LDAP_SERVER_VERIFY_NAME_OID" => "1.2.840.113556.1.4.1338", +"LDAP_SERVER_DOMAIN_SCOPE_OID" => "1.2.840.113556.1.4.1339", +"LDAP_SERVER_SEARCH_OPTIONS_OID" => "1.2.840.113556.1.4.1340", +"LDAP_SERVER_PERMISSIVE_MODIFY_OID" => "1.2.840.113556.1.4.1413", +"LDAP_SERVER_ASQ_OID" => "1.2.840.113556.1.4.1504", +"NONE (Get stats control)" => "1.2.840.113556.1.4.970", +"LDAP_SERVER_QUOTA_CONTROL_OID" => "1.2.840.113556.1.4.1852", +); + +my %ads_capabilities = ( +"LDAP_CAP_ACTIVE_DIRECTORY_OID" => "1.2.840.113556.1.4.800", +"LDAP_CAP_ACTIVE_DIRECTORY_V51_OID" => "1.2.840.113556.1.4.1670", +"LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID" => "1.2.840.113556.1.4.1791", +); + +my %ads_extensions = ( +"LDAP_START_TLS_OID" => "1.3.6.1.4.1.1466.20037", +"LDAP_TTL_EXTENDED_OP_OID" => "1.3.6.1.4.1.1466.101.119.1", +"LDAP_SERVER_FAST_BIND_OID" => "1.2.840.113556.1.4.1781", +"NONE (TTL refresh extended op)" => "1.3.6.1.4.1.1466.101.119.1", +); + +my %ads_matching_rules = ( +"LDAP_MATCHING_RULE_BIT_AND" => "1.2.840.113556.1.4.803", +"LDAP_MATCHING_RULE_BIT_OR" => "1.2.840.113556.1.4.804", +); + +my %wknguids = ( +"WELL_KNOWN_GUID_COMPUTERS" => "AA312825768811D1ADED00C04FD8D5CD", +"WELL_KNOWN_GUID_DOMAIN_CONTROLLERS" => "A361B2FFFFD211D1AA4B00C04FD7D83A", +"WELL_KNOWN_GUID_SYSTEM" => "AB1D30F3768811D1ADED00C04FD8D5CD", +"WELL_KNOWN_GUID_USERS" => "A9D1CA15768811D1ADED00C04FD8D5CD", +); + +my %ads_systemflags = ( +"FLAG_DONT_REPLICATE" => 0x00000001, # 1 +"FLAG_REPLICATE_TO_GC" => 0x00000002, # 2 +"FLAG_ATTRIBUTE_CONSTRUCT" => 0x00000004, # 4 +"FLAG_CATEGORY_1_OBJECT" => 0x00000010, # 16 +"FLAG_DELETE_WITHOUT_TOMBSTONE" => 0x02000000, # 33554432 +"FLAG_DOMAIN_DISALLOW_MOVE" => 0x04000000, # 67108864 +"FLAG_DOMAIN_DISALLOW_RENAME" => 0x08000000, # 134217728 +#"FLAG_CONFIG_CAN_MOVE_RESTRICTED" => 0x10000000, # 268435456 # only setable on creation +#"FLAG_CONFIG_CAN_MOVE" => 0x20000000, # 536870912 # only setable on creation +#"FLAG_CONFIG_CAN_RENAME" => 0x40000000, # 1073741824 # only setable on creation +"FLAG_DISALLOW_DELETE" => 0x80000000, # 2147483648 +); + +my %ads_mixed_domain = ( +"NATIVE_LEVEL_DOMAIN" => 0, +"MIXED_LEVEL_DOMAIN" => 1, +); + +my %ads_ds_func = ( +"DS_BEHAVIOR_WIN2000" => 0, # untested +"DS_BEHAVIOR_WIN2003" => 2, +); + +my %ads_instance_type = ( +"DS_INSTANCETYPE_IS_NC_HEAD" => 0x1, +"IT_WRITE" => 0x4, +"IT_NC_ABOVE" => 0x8, +); + +my %ads_uacc = ( + "ACCOUNT_NEVER_EXPIRES" => 0x000000, # 0 + "ACCOUNT_OK" => 0x800000, # 8388608 + "ACCOUNT_LOCKED_OUT" => 0x800010, # 8388624 +); + +my %munged_dial = ( + "CtxCfgPresent" => \&dump_int, + "CtxCfgFlags1" => \&dump_int, + "CtxCallback" => \&dump_string, + "CtxShadow" => \&dump_string, + "CtxMaxConnectionTime" => \&dump_int, + "CtxMaxDisconnectionTime"=> \&dump_int, + "CtxMaxIdleTime" => \&dump_int, + "CtxKeyboardLayout" => \&dump_int, + "CtxMinEncryptionLevel" => \&dump_int, + "CtxWorkDirectory" => \&dump_string, + "CtxNWLogonServer" => \&dump_string, + "CtxWFHomeDir" => \&dump_string, + "CtxWFHomeDirDrive" => \&dump_string, + "CtxWFProfilePath" => \&dump_string, + "CtxInitialProgram" => \&dump_string, + "CtxCallbackNumber" => \&dump_string, +); + + +$SIG{__WARN__} = sub { + use Carp; + Carp::cluck (shift); +}; + +# parse ads.h +parse_ads_h(); + +# if there is data missing, we try to autodetect with samba-tools (if installed) +# this might fill up workgroup, machine, realm +get_samba_info(); + +# get a workgroup +$workgroup = $workgroup || $opt_workgroup || ""; + +# get the server +$server = process_servername($opt_host) || + detect_server($workgroup,$opt_realm) || + die "please define server to query with -h host\n"; + + +# get the base +$base = $opt_base || + get_base_from_rootdse($server,$dse); + +# get the realm +$realm = $opt_realm || + get_realm_from_rootdse($server,$dse); + +# get sasl mechs +my @sasl_mechs = get_sasl_mechs_from_rootdse($server,$dse); +my $sasl_mech = "GSSAPI"; +if ($opt_saslmech) { + $sasl_mech = sprintf("%s", (check_sasl_mech($opt_saslmech) == 0)?uc($opt_saslmech):""); +} + +# set bind type +my $sasl_bind = 1 if (!$opt_simpleauth); + +# get username +my $user = check_user($opt_user) || $ENV{'USER'} || ""; + +# gen upn +my $upn = sprintf("%s", gen_upn($opt_machine ? "$machine\$" : $user, $realm)); + +# get binddn +$binddn = $opt_binddn || $upn; + +# get the password +$password = $password || $opt_password; +if (!$password) { + $password = $opt_machine ? get_machine_password($workgroup) : get_password(); +} + +my %attr_handler = ( + "accountExpires" => \&dump_nttime, + "badPasswordTime" => \&dump_nttime, + "creationTime" => \&dump_nttime, + "currentTime" => \&dump_timestr, + "domainControllerFunctionality" => \&dump_ds_func, + "domainFunctionality" => \&dump_ds_func, + "dSCorePropagationData" => \&dump_timestr, + "forceLogoff" => \&dump_nttime_abs, + "forestFunctionality" => \&dump_ds_func, + "groupType" => \&dump_gtype, + "instanceType" => \&dump_instance_type, + "lastLogon" => \&dump_nttime, + "lastLogonTimestamp" => \&dump_nttime, + "lockoutTime" => \&dump_nttime, + "lockoutDuration" => \&dump_nttime_abs, + "lockOutObservationWindow" => \&dump_nttime_abs, +# "logonHours" => \&dump_not_yet, + "maxPwdAge" => \&dump_nttime_abs, + "minPwdAge" => \&dump_nttime_abs, + "modifyTimeStamp" => \&dump_timestr, +# "msRADIUSFramedIPAddress" => \&dump_ipaddr, +# "msRASSavedFramedIPAddress" => \&dump_ipaddr, + "ntMixedDomain" => \&dump_mixed_domain, + "nTSecurityDescriptor" => \&dump_secdesc, + "objectGUID" => \&dump_guid, + "objectSid" => \&dump_sid, + "pwdLastSet" => \&dump_nttime, + "sAMAccountType" => \&dump_atype, + "systemFlags" => \&dump_systemflags, + "supportedControl", => \&dump_controls, + "supportedCapabilities", => \&dump_capabilities, + "supportedExtension", => \&dump_extension, + "tokenGroups", => \&dump_sid, + "userAccountControl" => \&dump_uac, + "msDS-User-Account-Control-Computed" => \&dump_uacc, + "userFlags" => \&dump_uf, + "userParameters" => \&dump_munged_dial, + "whenChanged" => \&dump_timestr, + "whenCreated" => \&dump_timestr, +); + + + +################ +# subfunctions # +################ + +sub usage { + print "usage: $0 [--base|-b base] [--debug level] [--debug level] [--DN|-D binddn] [--extendeddn|-e] [--help] [--host|-h host] [--machine|-P] [--metadata|-m] [--nodiffs] [--notify|-n] [--password|-w password] [--port port] [--rawdisplay] [--realm|-R realm] [--rootdse] [--saslmech|-Y saslmech] [--schema|-c] [--scope|-s scope] [--simpleauth|-x] [--starttls|-Z] [--user|-U user] [--wknguid] [--workgroup|-k workgroup] filter [attrs]\n"; + print "\t--base|-b [base]\n\t\tUse base [base]\n"; + print "\t--debug [level]\n\t\tUse debuglevel (for Net::LDAP)\n"; + print "\t--DN|-D [binddn]\n\t\tUse binddn or principal\n"; + print "\t--extendeddn|-e\n\t\tDisplay extended dn (LDAP_SERVER_EXTENDED_DN_OID)\n"; + print "\t--help\n\t\tDisplay help page\n"; + print "\t--host|-h [host]\n\t\tQuery Host [host] (either a hostname or an LDAP uri)\n"; + print "\t--machine|-P\n\t\tUse samba3 machine account stored in $secrets_tdb (needs root access)\n"; + print "\t--metdata|-m\n\t\tDisplay replication metadata\n"; + print "\t--nodiffs\n\t\tDisplay no diffs but full entry dump when running in notify mode\n"; + print "\t--notify|-n\n\t\tActivate asynchronous change notification (LDAP_SERVER_NOTIFICATION_OID)\n"; + print "\t--password|-w [password]\n\t\tUse [password] for binddn\n"; + print "\t--port [port]\n\t\tUse [port] when connecting ADS\n"; + print "\t--rawdisplay\n\t\tDo not interpret values\n"; + print "\t--realm|-R [realm]\n\t\tUse [realm] when trying to construct bind-principal\n"; + print "\t--rootdse\n\t\tDisplay RootDSE (anonymously)\n"; + print "\t--saslmech|-Y [saslmech]\n\t\tUse SASL Mechanism [saslmech] when binding\n"; + print "\t--schema|-c\n\t\tDisplay DSE-Schema\n"; + print "\t--scope|-s [scope]\n\t\tUse scope [scope] (sub, base, one)\n"; + print "\t--simpleauth|-x\n\t\tUse simple bind (otherwise SASL binds are performed)\n"; + print "\t--starttls|-Z\n\t\tUse Start TLS extended operation to secure LDAP traffic\n"; + print "\t--user|-U [user]\n\t\tUse [user]\n"; + print "\t--wknguid\n\t\tDisplay well known guids\n"; + print "\t--workgroup|-k [workgroup]\n\t\tWhen LDAP-Server is not known try to find a Domain-Controller for [workgroup]\n"; +} + +sub write_ads_list { + my ($mod,$attr,$value) = @_; + my $ofh = select(STDOUT); + $~ = "ADS_LIST"; + select($ofh); + write(); + +format ADS_LIST = +@<<<< @>>>>>>>>>>>>>>>>>>>>>>>: @* +$mod, $attr, $value +. +} + +sub write_ads { + my ($mod,$attr,$value) = @_; + my $ofh = select(STDOUT); + $~ = "ADS"; + select($ofh); + write(); + +format ADS = +@<<<< @>>>>>>>>>>>>>>>>>>>>>>>: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +$mod, $attr, $value +~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + $value +. +} + +sub detect_server { + + my $workgroup = shift; + my $realm = shift; + my $result; + my $found; + + # try net cache (nbt records) + if ( -x $net && $workgroup ) { + my $key = sprintf("NBT/%s#1C", uc($workgroup)); + chomp($result = `$net cache search $key 2>&1 /dev/null`); + $result =~ s/^.*Value: //; + $result =~ s/:.*//; + return $result if $result; + printf("%10s query failed for [%s]\n", "net cache", $key); + } + + # try dns SRV entries + if ( -x $dig && $realm ) { + my $key = sprintf("_ldap._tcp.%s", lc($realm)); + chomp($result = `$dig $key SRV +short +search | egrep "^[0-9]" | head -1`); + $result =~ s/.* //g; + $result =~ s/.$//g; + return $result if $result; + printf("%10s query failed for [%s]\n", "dns", $key); + } + + # try netbios broadcast query + if ( -x $nmblookup && $workgroup ) { + my $key = sprintf("%s#1C", uc($workgroup)); + my $pattern = sprintf("%s<1c>", uc($workgroup)); + chomp($result = `$nmblookup $key -d 0 | grep '$pattern'`); + $result =~ s/\s.*//; + return $result if $result; + printf("%10s query failed for [%s]\n", "nmblookup", $key); + } + + return ""; +} + +sub get_samba_info { + + if (! -x $testparm) { return -1; } + + my $tmp; + open(TESTPARM, "$testparm -s -v 2> /dev/null |"); + while (my $line = ) { + chomp($line); + if ($line =~ /netbios name/) { + ($tmp, $machine) = split(/=/, $line); + $machine =~ s/\s+|\t+//g; + } + if ($line =~ /realm/) { + ($tmp, $realm) = split(/=/, $line); + $realm =~ s/\s+|\t+//g; + } + if ($line =~ /workgroup/) { + ($tmp, $workgroup) = split(/=/, $line); + $workgroup =~ s/\s+|\t+//g; + } + } + close(TESTPARM); + return 0; +} + +sub gen_upn { + my $machine = shift; + my $realm = shift; + if ($machine && $realm) { + return sprintf("%s\@%s", lc($machine), uc($realm)); + }; + return undef; +} + +sub get_password { + if (!$password && $opt_simpleauth && check_ticket($user)) { + return prompt_password($user); + } + return ""; +} + +sub get_user { + my $user = shift || prompt_user(); + return $user; +} + +sub get_machine_password { + + my $workgroup = shift || ""; + $workgroup = uc($workgroup); + + my ($found, $tmp); + -x $tdbdump || die "tdbdump is not installed. cannot proceed autodetection\n"; + -r $secrets_tdb || die "cannot read $secrets_tdb. cannot proceed autodetection\n"; + + # get machine-password + my $key = sprintf("SECRETS/MACHINE_PASSWORD/%s", $workgroup); + open(SECRETS,"$tdbdump $secrets_tdb |"); + while(my $line = ) { + chomp($line); + if ($found) { + $line =~ s/\\00//; + ($line,$password) = split(/"/, $line); + last; + } + if ($line =~ /$key/) { + $found = 1; + } + } + close(SECRETS); + + if ($found) { + print "Successfully autodetected machine password for workgroup: $workgroup\n"; + return $password; + } else { + warn "No machine password available for $workgroup\n"; + } + return ""; +} + +sub prompt_password { + + my $acct = shift || ""; + if ($acct =~ /\%/) { + ($acct, $password) = split(/\%/, $acct); + return $password; + } + system "stty -echo"; + print "Enter password for $acct:"; + my $password = ; + chomp($password); + print "\n"; + system "stty echo"; + return $password; +} + +sub prompt_user { + + print "Enter Username:"; + my $user = ; + chomp($user); + print "\n"; + return $user; +} + +sub check_ticket { + return system("$klist -t"); +} + +sub get_ticket { + + my $KRB5_CONFIG = "/tmp/.krb5.conf.telads-$<"; + + open(KRB5CONF, "> $KRB5_CONFIG") || die "cannot write $KRB5_CONFIG"; + printf KRB5CONF "# autogenerated by $0\n"; + printf KRB5CONF "[libdefaults]\n\tdefault_realm = %s\n\tclockskew = %d\n", uc($realm), 60*60; + printf KRB5CONF "[realms]\n\t%s = {\n\t\tkdc = %s\n\t}\n", uc($realm), $server; + close(KRB5CONF); + + if ( system("KRB5_CONFIG=$KRB5_CONFIG $kinit $user") != 0) { + return -1; + } + + return 0; +} + +sub check_user { + my $acct = shift || ""; + if ($acct =~ /\%/) { + ($acct, $password) = split(/\%/, $acct); + } + return $acct; +} + +sub check_ctrls ($$@) { + + # bogus function?? + my $server = shift || ""; + $dse = shift || get_dse($server) || return -1; + my @ctrls = @_; + + my $dse_controls = $dse->get_value('supportedControl', asref => '1'); + my @dse_controls = @$dse_controls; + + foreach my $i (@ctrls) { + # we could use -> supported_control but this + # is only available in newer versions of perl-ldap +# if ( ! $dse->supported_control( $i ) ) { + if ( grep(/$i->type()/, @dse_controls) ) { + printf("required control: %s is not supported by ADS-server.\n", $i->type()); + return -1; + } + } + return 0; +} + +sub get_base_from_rootdse { + + my $server = shift || ""; + $dse = shift || get_dse($server,$async_ldap_hd) || return -1; + return $dse->get_value('defaultNamingContext'); +} + +sub get_realm_from_rootdse { + + my $server = shift || ""; + $dse = shift || get_dse($server,$async_ldap_hd) || return -1; + my $service = $dse->get_value('ldapServiceName') || ""; + if ($service) { + my ($t,$realm) = split(/\@/, $service); + return $realm; + } else { + die "very odd: could not get realm"; + } +} + +sub get_sasl_mechs_from_rootdse { + + my $server = shift || ""; + $dse = shift || get_dse($server,$async_ldap_hd) || return -1; + my $mechs = $dse->get_value('supportedSASLMechanisms', asref => 1); + return @$mechs; +} + +sub get_dse { + + my $server = shift || return undef; + $async_ldap_hd = shift || get_ldap_hd($server,1); + if (!$async_ldap_hd) { + print "oh, no connection\n"; + return undef; + } + my $mesg = $async_ldap_hd->bind() || die "cannot bind\n"; + if ($mesg->code) { die "failed to bind\n"; }; + my $dse = $async_ldap_hd->root_dse( attrs => ['*', "supportedExtension", "supportedFeatures" ] ); + + return $dse; +} + +sub process_servername { + + my $name = shift || return ""; + if ($name =~ /^ldaps:\/\//i ) { + $name =~ s#^ldaps://##i; + $uri = sprintf("%s://%s", "ldaps", $name); + } else { + $name =~ s#^ldap://##i; + $uri = sprintf("%s://%s", "ldap", $name); + } + return $name; +} + +sub get_ldap_hd { + + my $server = shift || return undef; + my $async = shift || "0"; + my $hd; + die "uri unavailable" if (!$uri); + if ($uri =~ /^ldaps:\/\//i ) { + $port = $port || 636; + use Net::LDAPS; + $hd = Net::LDAPS->new( $server, async => $async, port => $port ) || + die "host $server not available: $!"; + } else { + $port = $port || 389; + $hd = Net::LDAP->new( $server, async => $async, port => $port ) || + die "host $server not available: $!"; + } + $hd->debug($opt_debug); + if ($opt_starttls) { + $hd->start_tls( verify => 'none' ); + } + + return $hd; +} + +sub get_sasl_hd { + + if (!$have_sasl) { + print "no sasl support\n"; + return undef; + } + + my $hd; + if ($sasl_mech && $sasl_mech eq "GSSAPI") { + my $user = sprintf("%s\@%s", $user, uc($realm)); + if (check_ticket($user) != 0 && get_ticket($user) != 0) { + print "Could not get Kerberos ticket for user [$user]\n"; + return undef; + } + + $hd = Authen::SASL->new( mechanism => 'GSSAPI' ) || die "nope"; + my $conn = $hd->client_new("ldap", $server); + + if ($conn->code == -1) { + printf "%s\n", $conn->error(); + return undef; + }; + + } elsif ($sasl_mech) { + + # here comes generic sasl code + $hd = Authen::SASL->new( mechanism => $sasl_mech, + callback => { + user => \&get_user, + pass => \&get_password + } + ) || die "nope"; + } else { + $sasl_bind = 0; + print "no supported SASL mechanism found (@sasl_mechs).\n"; + print "falling back to simple bind.\n"; + return undef; + } + + return $hd; +} + +sub check_sasl_mech { + my $mech_check = shift; + my $have_mech = 0; + foreach my $mech (@sasl_mechs) { + $have_mech = 1 if ($mech eq uc($mech_check)); + } + if (!$have_mech) { + return -1; + } + return 0; +} + + +sub parse_ads_h { + + -e "$ads_h" || die "cannot open samba3 ads.h ($ads_h): $!"; + open(ADSH,"$ads_h"); + while (my $line = ) { + chomp($line); + if ($line =~ /#define.UF.*0x/) { + my ($tmp, $name, $val) = split(/\s+/,$line); + next if ($name =~ /UNUSED/); + $ads_uf{$name} = hex $val; + } + if ($line =~ /#define.GTYPE.*0x/) { + my ($tmp, $name, $val) = split(/\s+/,$line); + $ads_gtype{$name} = hex $val; + } + if ($line =~ /#define.ATYPE.*0x/) { + my ($tmp, $name, $val) = split(/\s+/,$line); + $ads_atype{$name} = + (exists $ads_atype{$val}) ? $ads_atype{$val} : hex $val; + } + } + close(ADSH); +} + +sub store_result ($) { + + my $entry = shift; + return if (!$entry); + $entry_store{$entry->dn} = $entry; +} + +sub display_result_diff ($) { + + my $entry_new = shift; + return if ( !$entry_new); + + if ( !exists $entry_store{$entry_new->dn}) { + print "can't display any differences yet. full dump...\n"; + display_entry_generic($entry_new); + return; + } + + my $entry_old = $entry_store{$entry_new->dn}; + + foreach my $attr (sort $entry_new->attributes) { + if ( $entry_new->exists($attr) && ! $entry_old->exists($attr)) { + display_attr_generic("add:\t", $entry_new, $attr); + next; + } + } + + foreach my $attr (sort $entry_old->attributes) { + if (! $entry_new->exists($attr) && $entry_old->exists($attr)) { + display_attr_generic("del:\t", $entry_old, $attr); + next; + } + + # now check for all values if they have changed, display changes + my ($old_vals, $new_vals, @old_vals, @new_vals, %old, %new); + + $old_vals = $entry_old->get_value($attr, asref => 1); + @old_vals = @$old_vals; + $new_vals = $entry_new->get_value($attr, asref => 1); + @new_vals = @$new_vals; + + if (scalar(@old_vals) == 1 && scalar(@new_vals) == 1) { + if ($old_vals[0] ne $new_vals[0]) { + display_attr_generic("old:\t", $entry_old, $attr); + display_attr_generic("new:\t", $entry_new, $attr); + } + next; + } + + # handle multivalued diffs + foreach my $val (@old_vals) { $old{$val} = "dummy"; }; + foreach my $val (@new_vals) { $new{$val} = "dummy"; }; + foreach my $val (sort keys %new) { + if (!exists $old{$val}) { + display_value_generic("add:\t", $attr, $val); + } + } + foreach my $val (sort keys %old) { + if (!exists $new{$val}) { + display_value_generic("del:\t", $attr, $val); + } + } + } + print "\n"; + +} + +sub sid2string ($) { + + my $binary_sid = shift; + my $inbuf2; + my $sid_rev; # [1] + my $num_auths; # [1] + my @id_auth; # [6] + my @sub_auths; + my $subauth; # [16] + my $sid_strout; + my $ia; + + my $tmp_sid = unpack 'H*', $binary_sid; + + # split the binary string + ($sid_rev, $num_auths, + $id_auth[0], $id_auth[1], $id_auth[2], $id_auth[3], $id_auth[4], $id_auth[5], + $sub_auths[0], $sub_auths[1], $sub_auths[2], $sub_auths[3], $sub_auths[4], $inbuf2) + = unpack 'H2 H2 H2 H2 H2 H2 H2 H2 h8 h8 h8 h8 h8 h*',"$binary_sid"; + + # don't ask... + for ( my $i = 0; $i < $num_auths; $i++ ) { + $sub_auths[$i] = reverse $sub_auths[$i]; + } + + # build the identifier authority + if ( ($id_auth[0] != 0) || ($id_auth[1] != 0) ) { + $ia = $id_auth[0]. + $id_auth[1]. + $id_auth[2]. + $id_auth[3]. + $id_auth[4]. + $id_auth[5]; + } else { + $ia = ($id_auth[5]) + + ($id_auth[4] << 8) + + ($id_auth[3] << 16) + + ($id_auth[2] << 24); + } + + # build the sid + $sid_strout = sprintf("S-%lu-%lu",hex($sid_rev),hex($ia)); + + for (my $i = 0; $i < $num_auths; $i++ ) { + $sid_strout .= sprintf( "-%lu", hex($sub_auths[$i]) ); + } + + return $sid_strout; +} + +sub string_to_guid { + my $string = shift; + return undef unless $string =~ /([0-9,a-z]{8})-([0-9,a-z]{4})-([0-9,a-z]{4})-([0-9,a-z]{2})([0-9,a-z]{2})-([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})/i; + + return pack("I", hex $1) . + pack("S", hex $2) . + pack("S", hex $3) . + pack("C", hex $4) . + pack("C", hex $5) . + pack("C", hex $6) . + pack("C", hex $7) . + pack("C", hex $8) . + pack("C", hex $9) . + pack("C", hex $10) . + pack("C", hex $11); + +# print "$1\n$2\n$3\n$4\n$5\n$6\n$7\n$8\n$9\n$10\n$11\n"; +} + +sub bindstring_to_guid { + my $str = shift; + return pack("H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2", + substr($str,0,2), + substr($str,2,2), + substr($str,4,2), + substr($str,6,2), + substr($str,8,2), + substr($str,10,2), + substr($str,12,2), + substr($str,14,2), + substr($str,16,2), + substr($str,18,2), + substr($str,20,2), + substr($str,22,2), + substr($str,24,2), + substr($str,26,2), + substr($str,28,2), + substr($str,30,2)); +} + +sub guid_to_string { + my $guid = shift; + my $string = sprintf "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + unpack("I", $guid), + unpack("S", substr($guid, 4, 2)), + unpack("S", substr($guid, 6, 2)), + unpack("C", substr($guid, 8, 1)), + unpack("C", substr($guid, 9, 1)), + unpack("C", substr($guid, 10, 1)), + unpack("C", substr($guid, 11, 1)), + unpack("C", substr($guid, 12, 1)), + unpack("C", substr($guid, 13, 1)), + unpack("C", substr($guid, 14, 1)), + unpack("C", substr($guid, 15, 1)); + return lc($string); +} + +sub guid_to_bindstring { + my $guid = shift; + return unpack("H" . 2 * length($guid), $guid), +} + +sub dump_wknguid { + print "Dumping Well known GUIDs:\n"; + foreach my $wknguid (keys %wknguids) { + + my $guid = bindstring_to_guid($wknguids{$wknguid}); + my $str = guid_to_string($guid); + my $back = guid_to_bindstring($guid); + + printf "wkguid: %s\n", $wknguid; + printf "bind_string format: %s\n", $wknguids{$wknguid}; + printf "string format: %s\n", guid_to_string($guid); + printf "back to bind_string:%s\n", guid_to_bindstring($guid); + + printf "use base: \"\"\n", guid_to_bindstring($guid), $base; + } +} + +sub gen_bitmask_string_format($%) { + my $mod = shift; + my (%tmp) = @_; + my @list; + foreach my $key (sort keys %tmp) { + push(@list, sprintf("%s %s", $tmp{$key}, $key)); + } + return join("\n$mod\t\t\t",@list); +} + +sub nt_to_unixtime ($) { + # the number of 100 nanosecond intervals since jan. 1. 1601 (utc) + my $t64 = shift; + $t64 =~ s/(.+).{7,7}/$1/; + $t64 -= 11644473600; + return $t64; +} + +sub dump_equal { + my $val = shift; + my $mod = shift || die "no mod"; + my (%header) = @_; + my %tmp; + my $found = 0; + foreach my $key (keys %header) { + if ($header{$key} eq $val) { + $tmp{"($val)"} = $key; + $found = 1; + last; + } + } + if (!$found) { $tmp{$val} = ""; }; + return gen_bitmask_string_format($mod,%tmp); +} + +sub dump_bitmask { + my $op = shift || die "no op"; + my $val = shift; + my $mod = shift || die "no mod"; + my (%header) = @_; + my %tmp; + $tmp{""} = $val; + foreach my $key (sort keys %header) { + if ($op eq "&") { + $tmp{$key} = ( $val & $header{$key} ) ? $set:$unset; + } elsif ($op eq "==") { + $tmp{$key} = ( $val == $header{$key} ) ? $set:$unset; + } else { + print "unknown operator: $op\n"; + return; + } + } + return gen_bitmask_string_format($mod,%tmp); +} + +sub dump_bitmask_and { + return dump_bitmask("&",@_); +} + +sub dump_bitmask_equal { + return dump_bitmask("==",@_); +} + +sub dump_uac { + return dump_bitmask_and(@_,%ads_uf); # ads_uf ? +} + +sub dump_uacc { + return dump_bitmask_equal(@_,%ads_uacc); +} + +sub dump_uf { + return dump_bitmask_and(@_,%ads_uf); +} + +sub dump_gtype { + return dump_bitmask_and(@_,%ads_gtype); +} + +sub dump_atype { + return dump_bitmask_equal(@_,%ads_atype); +} + +sub dump_controls { + return dump_equal(@_,%ads_controls); +} + +sub dump_capabilities { + return dump_equal(@_,%ads_capabilities); +} + +sub dump_extension { + return dump_equal(@_,%ads_extensions); +} + +sub dump_systemflags { + return dump_bitmask_and(@_,%ads_systemflags); +} + +sub dump_instance_type { + return dump_bitmask_and(@_,%ads_instance_type); +} + +sub dump_ds_func { + return dump_bitmask_equal(@_,%ads_ds_func); +} + +sub dump_mixed_domain { + return dump_bitmask_equal(@_,%ads_mixed_domain); +} + +sub dump_sid { + my $bin_sid = shift; + return sid2string($bin_sid); +} + +sub dump_guid { + my $guid = shift; + return guid_to_string($guid); +} + +sub dump_secdesc { + my $val = shift; + return "FIXME: write sddl-converter!"; +} + +sub dump_nttime { + my $nttime = shift; + if ($nttime == 0) { + return sprintf("%s (%s)", "never", $nttime); + } + my $localtime = localtime(nt_to_unixtime($nttime)); + return sprintf("%s (%s)", $localtime, $nttime); +} + +sub dump_nttime_abs { + if ($_[0] == 9223372036854775807) { + return sprintf("%s (%s)", "now", $_[0]); + } + if ($_[0] == -9223372036854775808 || $_[0] == 0) { # 0x7FFFFFFFFFFFFFFF + return sprintf("%s (%s)", "never", $_[0]); + } + # FIXME: actually *do* abs time ! + return dump_nttime($_[0]); +} + +sub dump_timestr { + my $time = shift; + my ($year,$mon,$mday,$hour,$min,$sec,$zone) = + unpack('a4 a2 a2 a2 a2 a2 a4', $time); + $mon -= 1; + my $localtime = localtime(timegm($sec,$min,$hour,$mday,$mon,$year)); + return sprintf("%s (%s)", $localtime, $time); +} + +sub dump_string { + return $_[0]; +} + +sub dump_int { + return sprintf("%d", $_[0]); +} + +sub dump_munged_dial { + my $dial = shift; + return "FIXME! decode this"; +} + +sub construct_filter { + + my $tmp = shift; + + if (!$tmp || $opt_notify) { + return "(objectclass=*)"; + } + + if ($tmp && $tmp !~ /^.*\=/) { + return "(ANR=$tmp)"; + } + + return $tmp; + # (&(objectCategory=person) + # (userAccountControl:$ads_matching_rules{LDAP_MATCHING_RULE_BIT_AND}:=2)) +} + +sub construct_attrs { + + my @attrs = @_; + + if (!@attrs) { + push(@attrs,"*"); + } + + if ($opt_notify) { + push(@attrs,"uSNChanged"); + } + + if ($opt_display_metadata) { + push(@attrs,"msDS-ReplAttributeMetaData"); + push(@attrs,"replPropertyMetaData"); + } + + push(@attrs,"nTSecurityDescriptor"); + push(@attrs,"msDS-KeyVersionNumber"); + push(@attrs,"msDS-User-Account-Control-Computed"); + push(@attrs,"modifyTimeStamp"); + + return sort @attrs; +} + +sub print_header { + + print "\n"; + printf "%10s: %s\n", "uri", $uri; + printf "%10s: %s\n", "port", $port; + printf "%10s: %s\n", "base", $base; + printf "%10s: %s\n", $sasl_bind ? "principal" : "binddn", $sasl_bind ? $upn : $binddn; + printf "%10s: %s\n", "password", $password; + printf "%10s: %s\n", "bind-type", $sasl_bind ? "SASL" : "simple"; + printf "%10s: %s\n", "sasl-mech", $sasl_mech if ($sasl_mech); + printf "%10s: %s\n", "filter", $filter; + printf "%10s: %s\n", "scope", $scope; + printf "%10s: %s\n", "attrs", join(", ", @attrs); + printf "%10s: %s\n", "controls", join(", ", @ctrls_s); + printf "%10s: %s\n", "page_size", $page_size if ($paging); + printf "%10s: %s\n", "start_tls", $opt_starttls ? "yes" : "no"; + printf "\n"; +} + +sub gen_controls { + + my $asn = Convert::ASN1->new; + $asn->prepare( + q< ExtendedDn ::= SEQUENCE { + mode INTEGER + } + > + ); + + my $ctl_extended_dn_val = $asn->encode( mode => '1'); + my $ctl_extended_dn =Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_EXTENDED_DN_OID'}, + critical => 'true', + value => $ctl_extended_dn_val); + + my $ctl_notification = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_NOTIFICATION_OID'}, + critical => 'true'); + + $ctl_paged = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_PAGED_RESULT_OID_STRING'}, + critical => 'true', + size => $page_size); + + if ($paging) { + push(@ctrls, $ctl_paged); + push(@ctrls_s, "LDAP_PAGED_RESULT_OID_STRING" ); + } + + if ($opt_display_extendeddn) { + push(@ctrls, $ctl_extended_dn); + push(@ctrls_s, "LDAP_SERVER_EXTENDED_DN_OID"); + } + if ($opt_notify) { + push(@ctrls, $ctl_notification); + push(@ctrls_s, "LDAP_SERVER_NOTIFICATION_OID"); + } + + return @ctrls; +} + +sub display_value_generic ($$$) { + + my ($mod,$attr,$value) = @_; + return unless (defined($value) and defined($attr)); + + if ( ! $opt_display_raw && exists $attr_handler{$attr} ) { + $value = $attr_handler{$attr}($value,$mod); + write_ads_list($mod,$attr,$value); + return; + } + write_ads($mod,$attr,$value); +} + +sub display_attr_generic ($$$) { + + my ($mod,$entry,$attr) = @_; + return if (!$attr || !$entry); + + my $ref = $entry->get_value($attr, asref => 1); + my @values = @$ref; + + foreach my $value (@values) { + display_value_generic($mod,$attr,$value); + } +} + +sub display_entry_generic ($) { + + my $entry = shift; + return if (!$entry); + + foreach my $attr ( $entry->attributes) { + display_attr_generic("\t",$entry,$attr); + } +} + +sub display_ldap_err ($) { + my $msg = shift; + + print_header(); + my ($package, $filename, $line, $subroutine) = caller(0); + + print "got error from ADS:\n"; + printf("%s(%d): ERROR (%s): %s\n", + $subroutine, $line, $msg->code, $msg->error); + +} + +sub process_result { + + my ($msg,$entry) = @_; + + if (!defined($msg)) { + return; + } + + if ($msg->code) { + display_ldap_err($msg); + exit 1; + } + + if (!defined($entry)) { + return; + } + + if ($entry->isa('Net::LDAP::Reference')) { + foreach my $ref ($entry->references) { + print "\ngot Reference: [$ref]\n"; + } + return; + } + + print "\nfound entry: ".$entry->dn."\n".("-" x 80)."\n"; + + display_entry_generic($entry); +} + +sub default_callback { + + my ($res,$obj) = @_; + + if (!$opt_notify) { + return process_result($res,$obj); + } +} + +sub error_callback { + + my ($msg,$entry) = @_; + + if (!$msg) { + return; + } + + if ($msg->code) { + display_ldap_err($msg); + exit(1); + } + return; +} + +sub notify_callback { + + my ($msg, $obj) = @_; + + if (! defined($obj)) { + return; + } + + if ($obj->isa('Net::LDAP::Reference')) { + foreach my $ref ($obj->references) { + print "\ngot Reference: [$ref]\n"; + } + return; + } + + while (1) { + + my $async_entry = $async_search->pop_entry; + + printf("\ngot changenotify for dn: [%s]\n%s\n", $async_entry->dn, ("-" x 80)); + + my $new_usn = $async_entry->get_value('uSNChanged'); + if (!$usn || $new_usn > $usn) { + $usn = $new_usn; + if ($opt_notify_nodiffs) { + display_entry_generic($async_entry); + } else { + display_result_diff($async_entry); + } + } + store_result($async_entry); + } +} + +sub do_bind($$) { + + my $async_ldap_hd = shift || return undef; + my $sasl_bind = shift; + + if ($sasl_bind) { + if (!$works_sasl) { + print "this version of Net::LDAP does not have proper SASL support.\n"; + print "Need at least perl-ldap V. $pref_version\n"; + } + $sasl_hd = get_sasl_hd(); + if (!$sasl_hd) { + print "failed to create SASL handle\n"; + return -1; + } + $mesg = $async_ldap_hd->bind( + sasl => $sasl_hd, + callback => \&error_callback + ) || die "doesnt work"; + } else { + $sasl_mech = ""; + $mesg = $async_ldap_hd->bind( + $binddn, + password => $password, + callback => \&error_callback + ) || die "doesnt work"; + }; + if ($mesg->code) { + display_ldap_err($mesg); + return -1; + } + return 0; +} + +sub do_unbind() { + if ($async_ldap_hd) { + $async_ldap_hd->unbind; + } + if ($sync_ldap_hd) { + $sync_ldap_hd->unbind; + } +} + +############################################################################### + +sub main () { + + $filter = construct_filter($query); + @attrs = construct_attrs(@attrs); + @ctrls = gen_controls(); + if (check_ctrls($server,$dse,@ctrls) == -1) { + print "not all required LDAP Controls are supported by this server\n"; + exit 1; + } + + if ($opt_dump_rootdse) { + print "Dumping Root-DSE:\n"; + display_entry_generic($dse); + exit 0; + } + + if ($opt_dump_wknguid) { + dump_wknguid(); + exit 0; + } + + if (do_bind($async_ldap_hd, $sasl_bind) == -1) { + exit 1; + } + + print_header(); + + if ($opt_dump_schema) { + print "Dumping Schema:\n"; + my $ads_schema = $async_ldap_hd->schema; + $ads_schema->dump; + exit 0; + } + + while (1) { + + $async_search = $async_ldap_hd->search( + base => $base, + filter => $filter, + attrs => [ @attrs ], + control => [ @ctrls ], + callback => \&default_callback, + scope => $scope, + ) || die "cannot search"; + + if ($opt_notify) { + + print "[$base] is registered now for change-notify\n"; + print "\nWaiting for change-notify...\n"; + + my $sync_ldap_hd = get_ldap_hd($server,0); + if (do_bind($sync_ldap_hd, $sasl_bind) == -1) { + exit 2; + } + + my $sync_search = $sync_ldap_hd->search( + base => $base, + filter => $filter, + attrs => [ @attrs ], + callback => \¬ify_callback, + scope => $scope, + ) || die "cannot search"; + + } + + $total_entry_count += $async_search->count; + ++$page_count; + print "-" x 80 . "\n"; + printf("Got %d Entries in Page %d \n\n", + $async_search->count, $page_count); + my ($resp) = $async_search->control( + $ads_controls{'LDAP_PAGED_RESULT_OID_STRING'} ) or last; + last unless ref $resp && $ctl_paged->cookie($resp->cookie); + } + + if ($async_search->entries == 0) { + print "No entries found with filter $filter\n"; + } else { + print "Got $total_entry_count Entries in $page_count Pages\n" if ($paging); + } + + do_unbind() +} + +main(); + +exit 0; -- cgit From 04564f690f4dfbfe142c6bebc48f7f1e74f81497 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Fri, 11 Mar 2005 12:24:24 +0000 Subject: r5743: Add perl-script to check for multiple LDAP-entries on request of Richard Sharpe. Users my run this script after they have vampired a windows domain controller to verify their system has no double sids, double uids, etc. Guenther (This used to be commit 31bd709a41e1bfe1f269a829c30e55a9538303df) --- examples/misc/check_multiple_LDAP_entries.pl | 201 +++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100755 examples/misc/check_multiple_LDAP_entries.pl (limited to 'examples/misc') diff --git a/examples/misc/check_multiple_LDAP_entries.pl b/examples/misc/check_multiple_LDAP_entries.pl new file mode 100755 index 0000000000..00c197ace4 --- /dev/null +++ b/examples/misc/check_multiple_LDAP_entries.pl @@ -0,0 +1,201 @@ +#!/usr/bin/perl -w +# Guenther Deschner +# +# check for multiple LDAP entries + +use strict; + +use Net::LDAP; +use Getopt::Std; + +my %opts; + +if (!@ARGV) { + print "usage: $0 -h host -b base -D admindn -w password [-l]\n"; + print "\tperforms checks for multiple sid, uid and gid-entries on your LDAP server\n"; + print "\t-l adds additional checks against the local /etc/passwd and /etc/group file\n"; + exit 1; +} + +getopts('b:h:D:w:l', \%opts); + +my $host = $opts{h} || "localhost"; +my $suffix = $opts{b} || die "please set base with -b"; +my $binddn = $opts{D} || die "please set basedn with -D"; +my $bindpw = $opts{w} || die "please set password with -w"; +my $check_local_files = $opts{l} || 0; + +######################## + + +my ($ldap, $res); +my (%passwd_h, %group_h); +my $bad_uids = 0; +my $bad_gids = 0; +my $bad_sids = 0; +my $ret = 0; + +if ($check_local_files) { + my @uids = `cut -d ':' -f 3 /etc/passwd`; + my @gids = `cut -d ':' -f 3 /etc/group`; + + foreach my $uid (@uids) { + chomp($uid); + $passwd_h{$uid} = $uid; + } + + foreach my $gid (@gids) { + chomp($gid); + $group_h{$gid} = $gid; + } +} + +######## +# bind # +######## + +$ldap = Net::LDAP->new($host, version => '3'); + +$res = $ldap->bind( $binddn, password => $bindpw); +$res->code && die "failed to bind: ", $res->error; + + + +########################### +# check for double sids # +########################### + +print "\ntesting for multiple sambaSids\n"; + +$res = $ldap->search( + base => $suffix, + filter => "(objectclass=sambaSamAccount)"); + +$res->code && die "failed to search: ", $res->error; + +foreach my $entry ($res->all_entries) { + + my $sid = $entry->get_value('sambaSid'); + + my $local_res = $ldap->search( + base => $suffix, + filter => "(&(objectclass=sambaSamAccount)(sambaSid=$sid))"); + + $local_res->code && die "failed to search: ", $local_res->error; + if ($local_res->count > 1) { + print "A SambaSamAccount with sambaSid [$sid] must exactly exist once\n"; + print "You have ", $local_res->count, " entries:\n"; + foreach my $loc_entry ($local_res->all_entries) { + printf "\t%s\n", $loc_entry->dn; + } + ++$bad_sids; + } +} + +if ($bad_sids) { + $ret = -1; + print "You have $bad_sids bad sambaSids in your system. You might need to repair them\n"; +} else { + print "No multiple sambaSids found in your system\n"; +} + +print "-" x 80, "\n"; + +########################### +# check for double groups # +########################### + +print "\ntesting for multiple gidNumbers\n"; + +$res = $ldap->search( + base => $suffix, + filter => "(objectclass=posixGroup)"); + +$res->code && die "failed to search: ", $res->error; + +foreach my $entry ($res->all_entries) { + + my $gid = $entry->get_value('gidNumber'); + my $dn = $entry->dn; + + my $local_res = $ldap->search( + base => $suffix, + filter => "(&(objectclass=posixGroup)(gidNumber=$gid))"); + + $local_res->code && die "failed to search: ", $local_res->error; + if ($local_res->count > 1) { + print "A PosixGroup with gidNumber [$gid] must exactly exist once\n"; + print "You have ", $local_res->count, " entries:\n"; + foreach my $loc_entry ($local_res->all_entries) { + printf "\t%s\n", $loc_entry->dn; + } + ++$bad_gids; + next; + } + + if ($check_local_files && exists $group_h{$gid}) { + print "Warning: There is a group in /etc/group that has gidNumber [$gid] as well\n"; + print "This entry may conflict with $dn\n"; + ++$bad_gids; + } +} + +if ($bad_gids) { + $ret = -1; + print "You have $bad_gids bad gidNumbers in your system. You might need to repair them\n"; +} else { + print "No multiple gidNumbers found in your system\n"; +} + +print "-" x 80, "\n"; + + +########################### +# check for double users # +########################### + +print "\ntesting for multiple uidNumbers\n"; + +$res = $ldap->search( + base => $suffix, + filter => "(objectclass=posixAccount)"); + +$res->code && die "failed to search: ", $res->error; + + +foreach my $entry ($res->all_entries) { + + my $uid = $entry->get_value('uidNumber'); + my $dn = $entry->dn; + + my $local_res = $ldap->search( + base => $suffix, + filter => "(&(objectclass=posixAccount)(uidNumber=$uid))"); + + $local_res->code && die "failed to search: ", $local_res->error; + if ($local_res->count > 1) { + print "A PosixAccount with uidNumber [$uid] must exactly exist once\n"; + print "You have ", $local_res->count, " entries:\n"; + foreach my $loc_entry ($local_res->all_entries) { + printf "\t%s\n", $loc_entry->dn; + } + ++$bad_uids; + next; + } + if ($check_local_files && exists $passwd_h{$uid}) { + print "Warning: There is a user in /etc/passwd that has uidNumber [$uid] as well\n"; + print "This entry may conflict with $dn\n"; + ++$bad_uids; + } +} + +if ($bad_uids) { + $ret = -1; + print "You have $bad_uids bad uidNumbers in your system. You might need to repair them\n"; +} else { + print "No multiple uidNumbers found in your system\n"; +} + +$ldap->unbind; + +exit $ret; -- cgit From c32197dd22587d58dfd5c2c129c402e22e1c9ef7 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Mon, 19 Dec 2005 02:15:13 +0000 Subject: r12336: A couple of fixes and enhancements for adssearch.pl (espc. to debug GPOs). sid2string fix from Michael James . Guenther (This used to be commit 9424b65c70bd24ba8f5b6c729dc1440a4dbf5647) --- examples/misc/adssearch.pl | 369 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 293 insertions(+), 76 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index 9bfc9e8a05..f9a7f94926 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -55,6 +55,7 @@ my $realm = ""; # parse input my ( + $opt_asq, $opt_base, $opt_binddn, $opt_debug, @@ -77,10 +78,12 @@ my ( $opt_simpleauth, $opt_starttls, $opt_user, + $opt_verbose, $opt_workgroup, ); GetOptions( + 'asq=s' => \$opt_asq, 'base|b=s' => \$opt_base, 'D|DN=s' => \$opt_binddn, 'debug=i' => \$opt_debug, @@ -102,6 +105,7 @@ GetOptions( 'simpleauth|x' => \$opt_simpleauth, 'tls|Z' => \$opt_starttls, 'user|U=s' => \$opt_user, + 'verbose|v' => \$opt_verbose, 'wknguid' => \$opt_dump_wknguid, 'workgroup|k=s' => \$opt_workgroup, ); @@ -129,11 +133,12 @@ my ($sasl_hd, $async_ldap_hd, $sync_ldap_hd); my ($mesg, $usn); my (%entry_store); my $async_search; -my (%ads_atype, %ads_gtype, %ads_uf); +my (%ads_atype, %ads_gtype, %ads_grouptype, %ads_uf); # fixed values and vars my $set = "X"; my $unset = "-"; +my $tabsize = "\t\t\t"; # get defaults my $scope = $opt_scope || "sub"; @@ -219,9 +224,112 @@ my %ads_instance_type = ( ); my %ads_uacc = ( - "ACCOUNT_NEVER_EXPIRES" => 0x000000, # 0 - "ACCOUNT_OK" => 0x800000, # 8388608 - "ACCOUNT_LOCKED_OUT" => 0x800010, # 8388624 + "ACCOUNT_NEVER_EXPIRES" => 0x000000, # 0 + "ACCOUNT_OK" => 0x800000, # 8388608 + "ACCOUNT_LOCKED_OUT" => 0x800010, # 8388624 +); + +my %ads_gpoptions = ( + "GPOPTIONS_INHERIT" => 0, + "GPOPTIONS_BLOCK_INHERITANCE" => 1, +); + +my %ads_gplink_opts = ( + "GPLINK_OPT_NONE" => 0, + "GPLINK_OPT_DISABLED" => 1, + "GPLINK_OPT_ENFORCED" => 2, +); + +my %ads_gpflags = ( + "GPFLAGS_ALL_ENABLED" => 0, + "GPFLAGS_USER_SETTINGS_DISABLED" => 1, + "GPFLAGS_MACHINE_SETTINGS_DISABLED" => 2, + "GPFLAGS_ALL_DISABLED" => 3, +); + +my %ads_serverstate = ( + "SERVER_ENABLED" => 1, + "SERVER_DISABLED" => 2, +); + +my %ads_sdeffective = ( + "OWNER_SECURITY_INFORMATION" => 0x01, + "DACL_SECURITY_INFORMATION" => 0x04, + "SACL_SECURITY_INFORMATION" => 0x10, +); + +my %ads_trustattrs = ( + "TRUST_ATTRIBUTE_NON_TRANSITIVE" => 1, + "TRUST_ATTRIBUTE_TREE_PARENT" => 2, + "TRUST_ATTRIBUTE_TREE_ROOT" => 3, + "TRUST_ATTRIBUTE_UPLEVEL_ONLY" => 4, +); + +my %ads_trustdirection = ( + "TRUST_DIRECTION_INBOUND" => 1, + "TRUST_DIRECTION_OUTBOUND" => 2, + "TRUST_DIRECTION_BIDIRECTIONAL" => 3, +); + +my %ads_trusttype = ( + "TRUST_TYPE_DOWNLEVEL" => 1, + "TRUST_TYPE_UPLEVEL" => 2, + "TRUST_TYPE_KERBEROS" => 3, + "TRUST_TYPE_DCE" => 4, +); + +my %ads_pwdproperties = ( + "DOMAIN_PASSWORD_COMPLEX" => 1, + "DOMAIN_PASSWORD_NO_ANON_CHANGE" => 2, + "DOMAIN_PASSWORD_NO_CLEAR_CHANGE" => 4, + "DOMAIN_LOCKOUT_ADMINS" => 8, + "DOMAIN_PASSWORD_STORE_CLEARTEXT" => 16, + "DOMAIN_REFUSE_PASSWORD_CHANGE" => 32, +); + +my %ads_uascompat = ( + "LANMAN_USER_ACCOUNT_SYSTEM_NOLIMITS" => 0, + "LANMAN_USER_ACCOUNT_SYSTEM_COMPAT" => 1, +); + +my %ads_frstypes = ( + "REPLICA_SET_SYSVOL" => 2, # unsure + "REPLICA_SET_DFS" => 1, # unsure + "REPLICA_SET_OTHER" => 0, # unsure +); + +my %ads_gp_cse_extensions = ( +"Administrative Templates Extension" => "35378EAC-683F-11D2-A89A-00C04FBBCFA2", +"Disk Quotas" => "3610EDA5-77EF-11D2-8DC5-00C04FA31A66", +"EFS Recovery" => "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A", +"Folder Redirection" => "25537BA6-77A8-11D2-9B6C-0000F8080861", +"IP Security" => "E437BC1C-AA7D-11D2-A382-00C04F991E27", +"Internet Explorer Maintenance" => "A2E30F80-D7DE-11d2-BBDE-00C04F86AE3B", +"QoS Packet Scheduler" => "426031c0-0b47-4852-b0ca-ac3d37bfcb39", +"Scripts" => "42B5FAAE-6536-11D2-AE5A-0000F87571E3", +"Security" => "827D319E-6EAC-11D2-A4EA-00C04F79F83A", +"Software Installation" => "C6DC5466-785A-11D2-84D0-00C04FB169F7", +); + +# guess work +my %ads_gpcextensions = ( +"Administrative Templates" => "0F6B957D-509E-11D1-A7CC-0000F87571E3", +"Certificates" => "53D6AB1D-2488-11D1-A28C-00C04FB94F17", +"EFS recovery policy processing" => "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A", +"Folder Redirection policy processing" => "25537BA6-77A8-11D2-9B6C-0000F8080861", +"Folder Redirection" => "88E729D6-BDC1-11D1-BD2A-00C04FB9603F", +"Registry policy processing" => "35378EAC-683F-11D2-A89A-00C04FBBCFA2", +"Remote Installation Services" => "3060E8CE-7020-11D2-842D-00C04FA372D4", +"Security Settings" => "803E14A0-B4FB-11D0-A0D0-00A0C90F574B", +"Security policy processing" => "827D319E-6EAC-11D2-A4EA-00C04F79F83A", +"unknown" => "3060E8D0-7020-11D2-842D-00C04FA372D4", +"unknown2" => "53D6AB1B-2488-11D1-A28C-00C04FB94F17", +); + +my %ads_gpo_default_guids = ( +"Default Domain Policy" => "31B2F340-016D-11D2-945F-00C04FB984F9", +"Default Domain Controllers Policy" => "6AC1786C-016F-11D2-945F-00C04fB984F9", +"mist" => "61718096-3D3F-4398-8318-203A48976F9E", ); my %munged_dial = ( @@ -243,7 +351,6 @@ my %munged_dial = ( "CtxCallbackNumber" => \&dump_string, ); - $SIG{__WARN__} = sub { use Carp; Carp::cluck (shift); @@ -299,45 +406,67 @@ if (!$password) { } my %attr_handler = ( + "Token-Groups-No-GC-Acceptable" => \&dump_sid, #wrong name "accountExpires" => \&dump_nttime, "badPasswordTime" => \&dump_nttime, "creationTime" => \&dump_nttime, "currentTime" => \&dump_timestr, "domainControllerFunctionality" => \&dump_ds_func, "domainFunctionality" => \&dump_ds_func, - "dSCorePropagationData" => \&dump_timestr, + "fRSReplicaSetGUID" => \&dump_guid, + "fRSReplicaSetType" => \&dump_frstype, + "fRSVersionGUID" => \&dump_guid, + "flags" => \&dump_gpflags, # fixme: possibly only on gpos! "forceLogoff" => \&dump_nttime_abs, "forestFunctionality" => \&dump_ds_func, +# "gPCMachineExtensionNames" => \&dump_gpcextensions, +# "gPCUserExtensionNames" => \&dump_gpcextensions, + "gPLink" => \&dump_gplink, + "gPOptions" => \&dump_gpoptions, "groupType" => \&dump_gtype, "instanceType" => \&dump_instance_type, "lastLogon" => \&dump_nttime, "lastLogonTimestamp" => \&dump_nttime, - "lockoutTime" => \&dump_nttime, - "lockoutDuration" => \&dump_nttime_abs, "lockOutObservationWindow" => \&dump_nttime_abs, -# "logonHours" => \&dump_not_yet, + "lockoutDuration" => \&dump_nttime_abs, + "lockoutTime" => \&dump_nttime, +# "logonHours" => \&dump_logonhours, "maxPwdAge" => \&dump_nttime_abs, "minPwdAge" => \&dump_nttime_abs, "modifyTimeStamp" => \&dump_timestr, + "msDS-Behavior-Version" => \&dump_ds_func, #unsure + "msDS-User-Account-Control-Computed" => \&dump_uacc, # "msRADIUSFramedIPAddress" => \&dump_ipaddr, # "msRASSavedFramedIPAddress" => \&dump_ipaddr, - "ntMixedDomain" => \&dump_mixed_domain, + "nTMixedDomain" => \&dump_mixed_domain, "nTSecurityDescriptor" => \&dump_secdesc, "objectGUID" => \&dump_guid, "objectSid" => \&dump_sid, + "pKT" => \&dump_pkt, + "pKTGuid" => \&dump_guid, "pwdLastSet" => \&dump_nttime, + "pwdProperties" => \&dump_pwdproperties, "sAMAccountType" => \&dump_atype, - "systemFlags" => \&dump_systemflags, - "supportedControl", => \&dump_controls, + "sDRightsEffective" => \&dump_sdeffective, + "securityIdentifier" => \&dump_sid, + "serverState" => \&dump_serverstate, "supportedCapabilities", => \&dump_capabilities, + "supportedControl", => \&dump_controls, "supportedExtension", => \&dump_extension, + "systemFlags" => \&dump_systemflags, "tokenGroups", => \&dump_sid, + "tokenGroupsGlobalAndUniversal" => \&dump_sid, + "trustAttributes" => \&dump_trustattr, + "trustDirection" => \&dump_trustdirection, + "trustType" => \&dump_trusttype, + "uASCompat" => \&dump_uascompat, "userAccountControl" => \&dump_uac, - "msDS-User-Account-Control-Computed" => \&dump_uacc, + "userCertificate" => \&dump_cert, "userFlags" => \&dump_uf, "userParameters" => \&dump_munged_dial, "whenChanged" => \&dump_timestr, "whenCreated" => \&dump_timestr, +# "dSCorePropagationData" => \&dump_timestr, ); @@ -347,7 +476,8 @@ my %attr_handler = ( ################ sub usage { - print "usage: $0 [--base|-b base] [--debug level] [--debug level] [--DN|-D binddn] [--extendeddn|-e] [--help] [--host|-h host] [--machine|-P] [--metadata|-m] [--nodiffs] [--notify|-n] [--password|-w password] [--port port] [--rawdisplay] [--realm|-R realm] [--rootdse] [--saslmech|-Y saslmech] [--schema|-c] [--scope|-s scope] [--simpleauth|-x] [--starttls|-Z] [--user|-U user] [--wknguid] [--workgroup|-k workgroup] filter [attrs]\n"; + print "usage: $0 [--asq] [--base|-b base] [--debug level] [--debug level] [--DN|-D binddn] [--extendeddn|-e] [--help] [--host|-h host] [--machine|-P] [--metadata|-m] [--nodiffs] [--notify|-n] [--password|-w password] [--port port] [--rawdisplay] [--realm|-R realm] [--rootdse] [--saslmech|-Y saslmech] [--schema|-c] [--scope|-s scope] [--simpleauth|-x] [--starttls|-Z] [--user|-U user] [--wknguid] [--workgroup|-k workgroup] filter [attrs]\n"; + print "\t--asq [attribute]\n\t\tAttribute to use for a attribute scoped query (LDAP_SERVER_ASQ_OID)\n"; print "\t--base|-b [base]\n\t\tUse base [base]\n"; print "\t--debug [level]\n\t\tUse debuglevel (for Net::LDAP)\n"; print "\t--DN|-D [binddn]\n\t\tUse binddn or principal\n"; @@ -547,6 +677,8 @@ sub prompt_user { } sub check_ticket { + return 0; + # works only for heimdal return system("$klist -t"); } @@ -740,18 +872,32 @@ sub parse_ads_h { chomp($line); if ($line =~ /#define.UF.*0x/) { my ($tmp, $name, $val) = split(/\s+/,$line); - next if ($name =~ /UNUSED/); + next if ($name =~ /UNUSED/); +# $ads_uf{$name} = sprintf("%d", hex $val); $ads_uf{$name} = hex $val; } - if ($line =~ /#define.GTYPE.*0x/) { + if ($line =~ /#define.GROUP_TYPE.*0x/) { my ($tmp, $name, $val) = split(/\s+/,$line); - $ads_gtype{$name} = hex $val; + $ads_grouptype{$name} = hex $val; } if ($line =~ /#define.ATYPE.*0x/) { my ($tmp, $name, $val) = split(/\s+/,$line); $ads_atype{$name} = (exists $ads_atype{$val}) ? $ads_atype{$val} : hex $val; } + if ($line =~ /#define.GTYPE.*0x/) { + my ($val, $i); + my ($tmp, $name, @val) = split(/\s+/,$line); + foreach my $tempval (@val) { + if ($tempval =~ /^0x/) { + $val = $tempval; + last; + } + } + next if (!$val); + $ads_gtype{$name} = sprintf("%d", hex $val); + } + } close(ADSH); } @@ -825,52 +971,12 @@ sub display_result_diff ($) { sub sid2string ($) { + # Fix from Michael James my $binary_sid = shift; - my $inbuf2; - my $sid_rev; # [1] - my $num_auths; # [1] - my @id_auth; # [6] - my @sub_auths; - my $subauth; # [16] - my $sid_strout; - my $ia; - - my $tmp_sid = unpack 'H*', $binary_sid; - - # split the binary string - ($sid_rev, $num_auths, - $id_auth[0], $id_auth[1], $id_auth[2], $id_auth[3], $id_auth[4], $id_auth[5], - $sub_auths[0], $sub_auths[1], $sub_auths[2], $sub_auths[3], $sub_auths[4], $inbuf2) - = unpack 'H2 H2 H2 H2 H2 H2 H2 H2 h8 h8 h8 h8 h8 h*',"$binary_sid"; - - # don't ask... - for ( my $i = 0; $i < $num_auths; $i++ ) { - $sub_auths[$i] = reverse $sub_auths[$i]; - } - - # build the identifier authority - if ( ($id_auth[0] != 0) || ($id_auth[1] != 0) ) { - $ia = $id_auth[0]. - $id_auth[1]. - $id_auth[2]. - $id_auth[3]. - $id_auth[4]. - $id_auth[5]; - } else { - $ia = ($id_auth[5]) + - ($id_auth[4] << 8) + - ($id_auth[3] << 16) + - ($id_auth[2] << 24); - } - - # build the sid - $sid_strout = sprintf("S-%lu-%lu",hex($sid_rev),hex($ia)); - - for (my $i = 0; $i < $num_auths; $i++ ) { - $sid_strout .= sprintf( "-%lu", hex($sub_auths[$i]) ); - } - - return $sid_strout; + my($sid_rev, $num_auths, $id1, $id2, @ids) = unpack("H2 H2 n N V*", $binary_sid); + my $sid_string = join("-", "S", hex($sid_rev), ($id1<<32)+$id2, @ids); + return $sid_string; + } sub string_to_guid { @@ -959,9 +1065,10 @@ sub gen_bitmask_string_format($%) { foreach my $key (sort keys %tmp) { push(@list, sprintf("%s %s", $tmp{$key}, $key)); } - return join("\n$mod\t\t\t",@list); + return join("\n$mod$tabsize",@list); } + sub nt_to_unixtime ($) { # the number of 100 nanosecond intervals since jan. 1. 1601 (utc) my $t64 = shift; @@ -994,7 +1101,7 @@ sub dump_bitmask { my (%header) = @_; my %tmp; $tmp{""} = $val; - foreach my $key (sort keys %header) { + foreach my $key (sort keys %header) { # sort by val ! if ($op eq "&") { $tmp{$key} = ( $val & $header{$key} ) ? $set:$unset; } elsif ($op eq "==") { @@ -1019,6 +1126,18 @@ sub dump_uac { return dump_bitmask_and(@_,%ads_uf); # ads_uf ? } +sub dump_uascompat { + return dump_bitmask_equal(@_,%ads_uascompat); +} + +sub dump_gpoptions { + return dump_bitmask_equal(@_,%ads_gpoptions); +} + +sub dump_gpflags { + return dump_bitmask_equal(@_,%ads_gpflags); +} + sub dump_uacc { return dump_bitmask_equal(@_,%ads_uacc); } @@ -1028,7 +1147,10 @@ sub dump_uf { } sub dump_gtype { - return dump_bitmask_and(@_,%ads_gtype); + my $ret = dump_bitmask_and(@_,%ads_grouptype); + $ret .= "\n$tabsize\t"; + $ret .= dump_bitmask_equal(@_,%ads_gtype); + return $ret; } sub dump_atype { @@ -1059,6 +1181,34 @@ sub dump_ds_func { return dump_bitmask_equal(@_,%ads_ds_func); } +sub dump_serverstate { + return dump_bitmask_equal(@_,%ads_serverstate); +} + +sub dump_sdeffective { + return dump_bitmask_and(@_,%ads_sdeffective); +} + +sub dump_trustattr { + return dump_bitmask_equal(@_,%ads_trustattrs); +} + +sub dump_trusttype { + return dump_bitmask_equal(@_,%ads_trusttype); +} + +sub dump_trustdirection { + return dump_bitmask_equal(@_,%ads_trustdirection); +} + +sub dump_pwdproperties { + return dump_bitmask_and(@_,%ads_pwdproperties); +} + +sub dump_frstype { + return dump_bitmask_equal(@_,%ads_frstypes) +} + sub dump_mixed_domain { return dump_bitmask_equal(@_,%ads_mixed_domain); } @@ -1100,6 +1250,9 @@ sub dump_nttime_abs { sub dump_timestr { my $time = shift; + if ($time eq "16010101000010.0Z") { + return sprintf("%s (%s)", "never", $time); + } my ($year,$mon,$mday,$hour,$min,$sec,$zone) = unpack('a4 a2 a2 a2 a2 a2 a4', $time); $mon -= 1; @@ -1120,6 +1273,37 @@ sub dump_munged_dial { return "FIXME! decode this"; } +sub dump_cert { + + my $cert = shift; + open(OPENSSL, "| /usr/bin/openssl x509 -text -inform der"); + print OPENSSL $cert; + close(OPENSSL); + return ""; +} + +sub dump_pkt { + my $pkt = shift; + return "not yet"; + printf("%s: ", $pkt); + printf("%02X", $pkt); + +} + +sub dump_gplink { + + my $gplink = shift; + my $gplink_mod = $gplink; + my @links = split("\\]\\[", $gplink_mod); + foreach my $link (@links) { + $link =~ s/^\[|\]$//g; + my ($ldap_link, $opt) = split(";", $link); + my @array = ( "$opt", "\t" ); + printf("%slink: %s, opt: %s\n", $tabsize, $ldap_link, dump_bitmask_and(@array, %ads_gplink_opts)); + } + return $gplink; +} + sub construct_filter { my $tmp = shift; @@ -1154,10 +1338,12 @@ sub construct_attrs { push(@attrs,"replPropertyMetaData"); } - push(@attrs,"nTSecurityDescriptor"); - push(@attrs,"msDS-KeyVersionNumber"); - push(@attrs,"msDS-User-Account-Control-Computed"); - push(@attrs,"modifyTimeStamp"); + if ($opt_verbose) { + push(@attrs,"nTSecurityDescriptor"); + push(@attrs,"msDS-KeyVersionNumber"); + push(@attrs,"msDS-User-Account-Control-Computed"); + push(@attrs,"modifyTimeStamp"); + } return sort @attrs; } @@ -1183,29 +1369,50 @@ sub print_header { sub gen_controls { - my $asn = Convert::ASN1->new; - $asn->prepare( + # setup attribute-scoped query control + my $asq_asn = Convert::ASN1->new; + $asq_asn->prepare( + q< asq ::= SEQUENCE { + sourceAttribute OCTET_STRING + } + > + ); + my $ctl_asq_val = $asq_asn->encode( sourceAttribute => $opt_asq); + my $ctl_asq = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_ASQ_OID'}, + critical => 'true', + value => $ctl_asq_val); + + + # setup extended dn control + my $asn_extended_dn = Convert::ASN1->new; + $asn_extended_dn->prepare( q< ExtendedDn ::= SEQUENCE { mode INTEGER } > ); - my $ctl_extended_dn_val = $asn->encode( mode => '1'); + my $ctl_extended_dn_val = $asn_extended_dn->encode( mode => '1'); my $ctl_extended_dn =Net::LDAP::Control->new( type => $ads_controls{'LDAP_SERVER_EXTENDED_DN_OID'}, critical => 'true', value => $ctl_extended_dn_val); + + # setup notify control my $ctl_notification = Net::LDAP::Control->new( type => $ads_controls{'LDAP_SERVER_NOTIFICATION_OID'}, critical => 'true'); + + # setup paging control $ctl_paged = Net::LDAP::Control->new( type => $ads_controls{'LDAP_PAGED_RESULT_OID_STRING'}, critical => 'true', size => $page_size); + if ($paging) { push(@ctrls, $ctl_paged); push(@ctrls_s, "LDAP_PAGED_RESULT_OID_STRING" ); @@ -1220,6 +1427,11 @@ sub gen_controls { push(@ctrls_s, "LDAP_SERVER_NOTIFICATION_OID"); } + if ($opt_asq) { + push(@ctrls, $ctl_asq); + push(@ctrls_s, "LDAP_SERVER_ASQ_OID"); + } + return @ctrls; } @@ -1244,7 +1456,7 @@ sub display_attr_generic ($$$) { my $ref = $entry->get_value($attr, asref => 1); my @values = @$ref; - foreach my $value (@values) { + foreach my $value ( sort @values) { display_value_generic($mod,$attr,$value); } } @@ -1254,14 +1466,14 @@ sub display_entry_generic ($) { my $entry = shift; return if (!$entry); - foreach my $attr ( $entry->attributes) { + foreach my $attr ( sort $entry->attributes) { display_attr_generic("\t",$entry,$attr); } } sub display_ldap_err ($) { - my $msg = shift; + my $msg = shift; print_header(); my ($package, $filename, $line, $subroutine) = caller(0); @@ -1342,6 +1554,11 @@ sub notify_callback { while (1) { my $async_entry = $async_search->pop_entry; + + if (!$async_entry->dn) { + print "very weird. entry has no dn\n"; + next; + } printf("\ngot changenotify for dn: [%s]\n%s\n", $async_entry->dn, ("-" x 80)); @@ -1450,7 +1667,7 @@ sub main () { if ($opt_notify) { - print "[$base] is registered now for change-notify\n"; + print "Base [$base] is registered now for change-notify\n"; print "\nWaiting for change-notify...\n"; my $sync_ldap_hd = get_ldap_hd($server,0); -- cgit From c1ffb8d9bcad9053f3d97dc89c3ff3b023401157 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 9 Feb 2006 10:24:27 +0000 Subject: r13410: Dump a netbootGUID as a GUID. Guenther (This used to be commit 9b19a68456c7b576750aaf64c178ba5323d9a95e) --- examples/misc/adssearch.pl | 1 + 1 file changed, 1 insertion(+) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index f9a7f94926..3651564ec2 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -438,6 +438,7 @@ my %attr_handler = ( "msDS-User-Account-Control-Computed" => \&dump_uacc, # "msRADIUSFramedIPAddress" => \&dump_ipaddr, # "msRASSavedFramedIPAddress" => \&dump_ipaddr, + "netbootGUID" => \&dump_guid, "nTMixedDomain" => \&dump_mixed_domain, "nTSecurityDescriptor" => \&dump_secdesc, "objectGUID" => \&dump_guid, -- cgit From b86c19795aadd45527694e6002cdd806e928cf38 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Tue, 25 Apr 2006 20:13:05 +0000 Subject: r15250: dump some more sids. Guenther (This used to be commit 2922c7f5704e3cfcc80dc648bb3d6d9aa80aaf37) --- examples/misc/adssearch.pl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index 3651564ec2..a26bb3b6c4 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -436,6 +436,7 @@ my %attr_handler = ( "modifyTimeStamp" => \&dump_timestr, "msDS-Behavior-Version" => \&dump_ds_func, #unsure "msDS-User-Account-Control-Computed" => \&dump_uacc, + "mS-DS-CreatorSID" => \&dump_sid, # "msRADIUSFramedIPAddress" => \&dump_ipaddr, # "msRASSavedFramedIPAddress" => \&dump_ipaddr, "netbootGUID" => \&dump_guid, @@ -457,6 +458,7 @@ my %attr_handler = ( "systemFlags" => \&dump_systemflags, "tokenGroups", => \&dump_sid, "tokenGroupsGlobalAndUniversal" => \&dump_sid, + "tokenGroupsNoGCAcceptable" => \&dump_sid, "trustAttributes" => \&dump_trustattr, "trustDirection" => \&dump_trustdirection, "trustType" => \&dump_trusttype, -- cgit From 72bc37cfa4fac9546326b3d0b2a4054b6d8a71b4 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Mon, 26 Jun 2006 16:14:40 +0000 Subject: r16521: Fix different extended_dn handling for win2k/2k3 (thanks to Frederic Brin at Novell). Guenther (This used to be commit f19f781e15da98cfaa94c71fc455fe095dac7b4d) --- examples/misc/adssearch.pl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index a26bb3b6c4..6a677fa205 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -87,7 +87,7 @@ GetOptions( 'base|b=s' => \$opt_base, 'D|DN=s' => \$opt_binddn, 'debug=i' => \$opt_debug, - 'extendeddn|e' => \$opt_display_extendeddn, + 'extendeddn|e=i' => \$opt_display_extendeddn, 'help' => \$opt_help, 'host|h=s' => \$opt_host, 'machine|P' => \$opt_machine, @@ -1396,12 +1396,12 @@ sub gen_controls { > ); - my $ctl_extended_dn_val = $asn_extended_dn->encode( mode => '1'); - my $ctl_extended_dn =Net::LDAP::Control->new( - type => $ads_controls{'LDAP_SERVER_EXTENDED_DN_OID'}, - critical => 'true', - value => $ctl_extended_dn_val); - + # only w2k3 accepts '1' and needs the ctl_val, w2k does not accept a ctl_val + my $ctl_extended_dn_val = $asn_extended_dn->encode( mode => $opt_display_extendeddn); + my $ctl_extended_dn = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_EXTENDED_DN_OID'}, + critical => 'true', + value => $opt_display_extendeddn ? $ctl_extended_dn_val : ""); # setup notify control my $ctl_notification = Net::LDAP::Control->new( @@ -1421,7 +1421,7 @@ sub gen_controls { push(@ctrls_s, "LDAP_PAGED_RESULT_OID_STRING" ); } - if ($opt_display_extendeddn) { + if (defined($opt_display_extendeddn)) { push(@ctrls, $ctl_extended_dn); push(@ctrls_s, "LDAP_SERVER_EXTENDED_DN_OID"); } -- cgit From ce815f38a7fb94ba842ed757d75668a8c19e4e99 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Fri, 30 Jun 2006 23:07:17 +0000 Subject: r16719: Automatically chase referrals, support LDAP fast bind exended operation and LDAP domain scope control. Guenther (This used to be commit 6df2a39110a3ae9d2729907472bad30f48896c86) --- examples/misc/adssearch.pl | 144 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 122 insertions(+), 22 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index 6a677fa205..f2be1ddcde 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -14,6 +14,7 @@ use strict; use Net::LDAP; use Net::LDAP::Control; +use Net::LDAP::Constant qw(LDAP_REFERRAL); use Convert::ASN1; use Time::Local; use POSIX qw(strftime); @@ -38,6 +39,8 @@ my $base = ""; my $binddn = ""; my $password = ""; my $server = ""; +my $rebind_url; + my $tdbdump = "/usr/bin/tdbdump"; my $testparm = "/usr/bin/testparm"; @@ -48,7 +51,6 @@ my $secrets_tdb = "/etc/samba/secrets.tdb"; my $klist = "/usr/bin/klist"; my $kinit = "/usr/bin/kinit"; my $ads_h = "/home/gd/ads.h"; -my $page_size = "1000"; my $workgroup = ""; my $machine = ""; my $realm = ""; @@ -62,14 +64,17 @@ my ( $opt_display_extendeddn, $opt_display_metadata, $opt_display_raw, + $opt_domain_scope, $opt_dump_rootdse, $opt_dump_schema, $opt_dump_wknguid, + $opt_fastbind, $opt_help, $opt_host, $opt_machine, $opt_notify, - $opt_notify_nodiffs, + $opt_notify_nodiffs, + $opt_paging, $opt_password, $opt_port, $opt_realm, @@ -87,13 +92,16 @@ GetOptions( 'base|b=s' => \$opt_base, 'D|DN=s' => \$opt_binddn, 'debug=i' => \$opt_debug, - 'extendeddn|e=i' => \$opt_display_extendeddn, + 'domain_scope' => \$opt_domain_scope, + 'extendeddn|e:i' => \$opt_display_extendeddn, + 'fastbind' => \$opt_fastbind, 'help' => \$opt_help, 'host|h=s' => \$opt_host, 'machine|P' => \$opt_machine, 'metadata|m' => \$opt_display_metadata, 'nodiffs' => \$opt_notify_nodiffs, 'notify|n' => \$opt_notify, + 'paging:i' => \$opt_paging, 'password|w=s' => \$opt_password, 'port=i' => \$opt_port, 'rawdisplay' => \$opt_display_raw, @@ -111,20 +119,27 @@ GetOptions( ); -# activate controls -my $paging = 1 if !$opt_notify; - if (!@ARGV && !$opt_dump_schema && !$opt_dump_rootdse && !$opt_notify || $opt_help) { usage(); exit 1; } +if ($opt_fastbind && !$opt_simpleauth) { + printf("LDAP fast bind can only be performed with simple binds\n"); + exit 1; +} + +if ($opt_notify) { + $opt_paging = 0; +} + # get the query my $query = shift; my @attrs = @ARGV; # some global vars -my ($filter, $dse, $uri); +my $filter = ""; +my ($dse, $uri); my ($attr, $value); my (@ctrls, @ctrls_s); my ($ctl_paged, $cookie); @@ -483,14 +498,17 @@ sub usage { print "\t--asq [attribute]\n\t\tAttribute to use for a attribute scoped query (LDAP_SERVER_ASQ_OID)\n"; print "\t--base|-b [base]\n\t\tUse base [base]\n"; print "\t--debug [level]\n\t\tUse debuglevel (for Net::LDAP)\n"; + print "\t--domain_scope\n\t\tLimit LDAP search to local domain (LDAP_SERVER_DOMAIN_SCOPE_OID)\n"; print "\t--DN|-D [binddn]\n\t\tUse binddn or principal\n"; - print "\t--extendeddn|-e\n\t\tDisplay extended dn (LDAP_SERVER_EXTENDED_DN_OID)\n"; + print "\t--extendeddn|-e [value]\n\t\tDisplay extended dn (LDAP_SERVER_EXTENDED_DN_OID)\n"; + print "\t--fastbind\n\t\tDo LDAP fast bind using LDAP_SERVER_FAST_BIND_OID extension\n"; print "\t--help\n\t\tDisplay help page\n"; print "\t--host|-h [host]\n\t\tQuery Host [host] (either a hostname or an LDAP uri)\n"; print "\t--machine|-P\n\t\tUse samba3 machine account stored in $secrets_tdb (needs root access)\n"; print "\t--metdata|-m\n\t\tDisplay replication metadata\n"; print "\t--nodiffs\n\t\tDisplay no diffs but full entry dump when running in notify mode\n"; print "\t--notify|-n\n\t\tActivate asynchronous change notification (LDAP_SERVER_NOTIFICATION_OID)\n"; + print "\t--paging [pagesize]\n\t\tUse paged results when searching\n"; print "\t--password|-w [password]\n\t\tUse [password] for binddn\n"; print "\t--port [port]\n\t\tUse [port] when connecting ADS\n"; print "\t--rawdisplay\n\t\tDo not interpret values\n"; @@ -710,28 +728,43 @@ sub check_user { return $acct; } -sub check_ctrls ($$@) { +sub check_root_dse($$$@) { # bogus function?? my $server = shift || ""; $dse = shift || get_dse($server) || return -1; - my @ctrls = @_; + my $attr = shift || die "unknown query"; + my @array = @_; - my $dse_controls = $dse->get_value('supportedControl', asref => '1'); - my @dse_controls = @$dse_controls; + my $dse_list = $dse->get_value($attr, asref => '1'); + my @dse_array = @$dse_list; - foreach my $i (@ctrls) { + foreach my $i (@array) { # we could use -> supported_control but this # is only available in newer versions of perl-ldap # if ( ! $dse->supported_control( $i ) ) { - if ( grep(/$i->type()/, @dse_controls) ) { - printf("required control: %s is not supported by ADS-server.\n", $i->type()); + if ( grep(/$i->type()/, @dse_array) ) { + printf("required \"$attr\": %s is not supported by ADS-server.\n", $i->type()); return -1; } } return 0; } +sub check_ctrls ($$@) { + my $server = shift; + my $dse = shift; + my @array = @_; + return check_root_dse($server, $dse, "supportedControl", @array); +} + +sub check_exts ($$@) { + my $server = shift; + my $dse = shift; + my @array = @_; + return check_root_dse($server, $dse, "supportedExtension", @array); +} + sub get_base_from_rootdse { my $server = shift || ""; @@ -1365,7 +1398,7 @@ sub print_header { printf "%10s: %s\n", "scope", $scope; printf "%10s: %s\n", "attrs", join(", ", @attrs); printf "%10s: %s\n", "controls", join(", ", @ctrls_s); - printf "%10s: %s\n", "page_size", $page_size if ($paging); + printf "%10s: %s\n", "page_size", $opt_paging if ($opt_paging); printf "%10s: %s\n", "start_tls", $opt_starttls ? "yes" : "no"; printf "\n"; } @@ -1413,10 +1446,15 @@ sub gen_controls { $ctl_paged = Net::LDAP::Control->new( type => $ads_controls{'LDAP_PAGED_RESULT_OID_STRING'}, critical => 'true', - size => $page_size); + size => $opt_paging ? $opt_paging : 1000); + # setup domscope control + my $ctl_domscope = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_DOMAIN_SCOPE_OID'}, + critical => 'true', + value => ""); - if ($paging) { + if (defined($opt_paging)) { push(@ctrls, $ctl_paged); push(@ctrls_s, "LDAP_PAGED_RESULT_OID_STRING" ); } @@ -1434,7 +1472,12 @@ sub gen_controls { push(@ctrls, $ctl_asq); push(@ctrls_s, "LDAP_SERVER_ASQ_OID"); } - + + if ($opt_domain_scope) { + push(@ctrls, $ctl_domscope); + push(@ctrls_s, "LDAP_SERVER_DOMAIN_SCOPE_OID"); + } + return @ctrls; } @@ -1519,6 +1562,10 @@ sub default_callback { my ($res,$obj) = @_; + if ($res->code == LDAP_REFERRAL) { + return; + } + if (!$opt_notify) { return process_result($res,$obj); } @@ -1566,6 +1613,9 @@ sub notify_callback { printf("\ngot changenotify for dn: [%s]\n%s\n", $async_entry->dn, ("-" x 80)); my $new_usn = $async_entry->get_value('uSNChanged'); + if (!$new_usn) { + die "odd, no usnChanged attribute???"; + } if (!$usn || $new_usn > $usn) { $usn = $new_usn; if ($opt_notify_nodiffs) { @@ -1602,16 +1652,39 @@ sub do_bind($$) { $mesg = $async_ldap_hd->bind( $binddn, password => $password, - callback => \&error_callback + callback => $opt_fastbind ? undef : \&error_callback ) || die "doesnt work"; }; if ($mesg->code) { - display_ldap_err($mesg); + display_ldap_err($mesg) if (!$opt_fastbind); return -1; } return 0; } +sub do_fast_bind() { + + do_unbind(); + + my $hd = get_ldap_hd($server,1); + + my $mesg = $hd->extension( + name => $ads_extensions{'LDAP_SERVER_FAST_BIND_OID'}); + + if ($mesg->code) { + display_ldap_err($mesg); + return -1; + } + + my $ret = do_bind($hd, undef); + $hd->unbind; + + printf("bind using 'LDAP_SERVER_FAST_BIND_OID' %s\n", + $ret == 0 ? "succeeded" : "failed"); + + return $ret; +} + sub do_unbind() { if ($async_ldap_hd) { $async_ldap_hd->unbind; @@ -1625,9 +1698,21 @@ sub do_unbind() { sub main () { + if ($opt_fastbind) { + + if (check_exts($server,$dse,"LDAP_SERVER_FAST_BIND_OID") == -1) { + print "LDAP_SERVER_FAST_BIND_OID not supported by this server\n"; + exit 1; + } + + # fast bind can only bind, not search + exit do_fast_bind(); + } + $filter = construct_filter($query); @attrs = construct_attrs(@attrs); @ctrls = gen_controls(); + if (check_ctrls($server,$dse,@ctrls) == -1) { print "not all required LDAP Controls are supported by this server\n"; exit 1; @@ -1668,6 +1753,21 @@ sub main () { scope => $scope, ) || die "cannot search"; + if ($async_search->code == LDAP_REFERRAL) { + foreach my $ref ($async_search->referrals) { + print "\ngot Referral: [$ref]\n"; + $async_ldap_hd->unbind(); + $async_ldap_hd = get_ldap_hd($ref, 1); + if (do_bind($async_ldap_hd, $sasl_bind) == -1) { + $async_ldap_hd->unbind(); + next; + } + print "\nsuccessful rebind to: [$ref]\n"; + last; + } + next; # repeat the query + } + if ($opt_notify) { print "Base [$base] is registered now for change-notify\n"; @@ -1701,7 +1801,7 @@ sub main () { if ($async_search->entries == 0) { print "No entries found with filter $filter\n"; } else { - print "Got $total_entry_count Entries in $page_count Pages\n" if ($paging); + print "Got $total_entry_count Entries in $page_count Pages\n" if ($opt_paging); } do_unbind() -- cgit From 89100480e8693ed0ad248b5c59187dec92c1fbb9 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Tue, 19 Sep 2006 22:57:13 +0000 Subject: r18697: Make sure that adssearch.pl does not * chase referrals * use paged search control when using the LDAP change notify control for monitoring changes. Guenther (This used to be commit d6849a83c01ee444931ffaa34c77b5fb7f4c8a5c) --- examples/misc/adssearch.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index f2be1ddcde..70c8f37cd4 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -130,7 +130,7 @@ if ($opt_fastbind && !$opt_simpleauth) { } if ($opt_notify) { - $opt_paging = 0; + $opt_paging = undef; } # get the query @@ -1562,7 +1562,7 @@ sub default_callback { my ($res,$obj) = @_; - if ($res->code == LDAP_REFERRAL) { + if (!$opt_notify && $res->code == LDAP_REFERRAL) { return; } @@ -1753,7 +1753,7 @@ sub main () { scope => $scope, ) || die "cannot search"; - if ($async_search->code == LDAP_REFERRAL) { + if (!$opt_notify && ($async_search->code == LDAP_REFERRAL)) { foreach my $ref ($async_search->referrals) { print "\ngot Referral: [$ref]\n"; $async_ldap_hd->unbind(); -- cgit From 2c3aa76510aa4e79f887d9c5cb05b8d04187aa38 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Mon, 16 Oct 2006 20:27:08 +0000 Subject: r19345: Allow better rootdse searches. Guenther (This used to be commit 27fbd85300c810cd06f4df514b6a762f8eac84d5) --- examples/misc/adssearch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index 70c8f37cd4..943a755a12 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -388,7 +388,7 @@ $server = process_servername($opt_host) || # get the base -$base = $opt_base || +$base = defined($opt_base)? $opt_base : "" || get_base_from_rootdse($server,$dse); # get the realm -- cgit From 24faef672eb6970a316921529652131fa2acf729 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 16 Nov 2006 11:55:16 +0000 Subject: r19745: For the fun of it, add an CLDAP client written in perl. Guenther (This used to be commit 8a2dded7fb6fff7080a77895803f28985bdf728b) --- examples/misc/cldap.pl | 466 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100755 examples/misc/cldap.pl (limited to 'examples/misc') diff --git a/examples/misc/cldap.pl b/examples/misc/cldap.pl new file mode 100755 index 0000000000..2218537f08 --- /dev/null +++ b/examples/misc/cldap.pl @@ -0,0 +1,466 @@ +#!/usr/bin/perl -w + +# Copyright (C) Guenther Deschner 2006 + +use strict; +use IO::Socket; +use Convert::ASN1 qw(:debug); +use Getopt::Long; + +# TODO: timeout handling, user CLDAP query + +################################## + +my $server = ""; +my $domain = ""; +my $host = ""; + +################################## + +my ( + $opt_debug, + $opt_domain, + $opt_help, + $opt_host, + $opt_server, +); + +my %cldap_flags = ( + ADS_PDC => 0x00000001, # DC is PDC + ADS_GC => 0x00000004, # DC is a GC of forest + ADS_LDAP => 0x00000008, # DC is an LDAP server + ADS_DS => 0x00000010, # DC supports DS + ADS_KDC => 0x00000020, # DC is running KDC + ADS_TIMESERV => 0x00000040, # DC is running time services + ADS_CLOSEST => 0x00000080, # DC is closest to client + ADS_WRITABLE => 0x00000100, # DC has writable DS + ADS_GOOD_TIMESERV => 0x00000200, # DC has hardware clock (and running time) + ADS_NDNC => 0x00000400, # DomainName is non-domain NC serviced by LDAP server +); + +my %cldap_samlogon_types = ( + SAMLOGON_AD_UNK_R => 23, + SAMLOGON_AD_R => 25, +); + +my $MAX_DNS_LABEL = 255 + 1; + +my %cldap_netlogon_reply = ( + type => 0, + flags => 0x0, + guid => 0, + forest => undef, + domain => undef, + hostname => undef, + netbios_domain => undef, + netbios_hostname => undef, + unk => undef, + user_name => undef, + server_site_name => undef, + client_site_name => undef, + version => 0, + lmnt_token => 0x0, + lm20_token => 0x0, +); + +sub usage { + print "usage: $0 [--domain|-d domain] [--help] [--host|-h host] [--server|-s server]\n\n"; +} + +sub connect_cldap ($) { + + my $server = shift || return undef; + + return IO::Socket::INET->new( + PeerAddr => $server, + PeerPort => 389, + Proto => 'udp', + Type => SOCK_DGRAM, + Timeout => 10, + ); +} + +sub send_cldap_netlogon ($$$$) { + + my ($sock, $domain, $host, $ntver) = @_; + + my $asn_cldap_req = Convert::ASN1->new; + + $asn_cldap_req->prepare(q< + + SEQUENCE { + msgid INTEGER, + [APPLICATION 3] SEQUENCE { + basedn OCTET STRING, + scope ENUMERATED, + dereference ENUMERATED, + sizelimit INTEGER, + timelimit INTEGER, + attronly BOOLEAN, + [CONTEXT 0] SEQUENCE { + [CONTEXT 3] SEQUENCE { + dnsdom_attr OCTET STRING, + dnsdom_val OCTET STRING + } + [CONTEXT 3] SEQUENCE { + host_attr OCTET STRING, + host_val OCTET STRING + } + [CONTEXT 3] SEQUENCE { + ntver_attr OCTET STRING, + ntver_val OCTET STRING + } + } + SEQUENCE { + netlogon OCTET STRING + } + } + } + >); + + my $pdu_req = $asn_cldap_req->encode( + msgid => 0, + basedn => "", + scope => 0, + dereference => 0, + sizelimit => 0, + timelimit => 0, + attronly => 0, + dnsdom_attr => $domain ? 'DnsDomain' : "", + dnsdom_val => $domain ? $domain : "", + host_attr => 'Host', + host_val => $host, + ntver_attr => 'NtVer', + ntver_val => $ntver, + netlogon => 'NetLogon', + ) || die "failed to encode pdu: $@"; + + if ($opt_debug) { + asn_dump($pdu_req); + } + + return $sock->send($pdu_req) || die "no send: $@"; +} + +# from source/libads/cldap.c : +# +#/* +# These seem to be strings as described in RFC1035 4.1.4 and can be: +# +# - a sequence of labels ending in a zero octet +# - a pointer +# - a sequence of labels ending with a pointer +# +# A label is a byte where the first two bits must be zero and the remaining +# bits represent the length of the label followed by the label itself. +# Therefore, the length of a label is at max 64 bytes. Under RFC1035, a +# sequence of labels cannot exceed 255 bytes. +# +# A pointer consists of a 14 bit offset from the beginning of the data. +# +# struct ptr { +# unsigned ident:2; // must be 11 +# unsigned offset:14; // from the beginning of data +# }; +# +# This is used as a method to compress the packet by eliminated duplicate +# domain components. Since a UDP packet should probably be < 512 bytes and a +# DNS name can be up to 255 bytes, this actually makes a lot of sense. +#*/ + +sub pull_netlogon_string (\$$$) { + + my ($ret, $ptr, $str) = @_; + + my $pos = $ptr; + + my $followed_ptr = 0; + my $ret_len = 0; + + my $retp = pack("x$MAX_DNS_LABEL"); + + do { + + $ptr = unpack("c", substr($str, $pos, 1)); + $pos++; + + if (($ptr & 0xc0) == 0xc0) { + + my $len; + + if (!$followed_ptr) { + $ret_len += 2; + $followed_ptr = 1; + } + + my $tmp0 = $ptr; #unpack("c", substr($str, $pos-1, 1)); + my $tmp1 = unpack("c", substr($str, $pos, 1)); + + if ($opt_debug) { + printf("tmp0: 0x%x\n", $tmp0); + printf("tmp1: 0x%x\n", $tmp1); + } + + $len = (($tmp0 & 0x3f) << 8) | $tmp1; + $ptr = unpack("c", substr($str, $len, 1)); + $pos = $len; + + } elsif ($ptr) { + + my $len = scalar $ptr; + + if ($len + 1 > $MAX_DNS_LABEL) { + warn("invalid string size: %d", $len + 1); + return 0; + } + + $ptr = unpack("a*", substr($str, $pos, $len)); + + $retp = sprintf("%s%s\.", $retp, $ptr); + + $pos += $len; + if (!$followed_ptr) { + $ret_len += $len + 1; + } + } + + } while ($ptr); + + $retp =~ s/\.$//; #ugly hack... + + $$ret = $retp; + + return $followed_ptr ? $ret_len : $ret_len + 1; +} + +sub dump_cldap_flags ($) { + + my $flags = shift || return; + printf("Flags:\n". + "\tIs a PDC: %s\n". + "\tIs a GC of the forest: %s\n". + "\tIs an LDAP server: %s\n". + "\tSupports DS: %s\n". + "\tIs running a KDC: %s\n". + "\tIs running time services: %s\n". + "\tIs the closest DC: %s\n". + "\tIs writable: %s\n". + "\tHas a hardware clock: %s\n". + "\tIs a non-domain NC serviced by LDAP server: %s\n", + ($flags & $cldap_flags{ADS_PDC}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_GC}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_LDAP}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_DS}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_KDC}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_TIMESERV}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_CLOSEST}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_WRITABLE}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_GOOD_TIMESERV}) ? "yes" : "no", + ($flags & $cldap_flags{ADS_NDNC}) ? "yes" : "no"); +} + +sub guid_to_string ($) { + + my $guid = shift || return undef; + if ((my $len = length $guid) != 16) { + printf("invalid length: %d\n", $len); + return undef; + } + my $string = sprintf "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + unpack("I", $guid), + unpack("S", substr($guid, 4, 2)), + unpack("S", substr($guid, 6, 2)), + unpack("C", substr($guid, 8, 1)), + unpack("C", substr($guid, 9, 1)), + unpack("C", substr($guid, 10, 1)), + unpack("C", substr($guid, 11, 1)), + unpack("C", substr($guid, 12, 1)), + unpack("C", substr($guid, 13, 1)), + unpack("C", substr($guid, 14, 1)), + unpack("C", substr($guid, 15, 1)); + return lc($string); +} + +sub recv_cldap_netlogon ($\$) { + + my ($sock, $return_string) = @_; + my ($ret, $pdu_out); + + $ret = $sock->recv($pdu_out, 8192) || die "failed to read from socket: $@"; + #$ret = sysread($sock, $pdu_out, 8192); + + if ($opt_debug) { + asn_dump($pdu_out); + } + + my $asn_cldap_rep = Convert::ASN1->new; + + $asn_cldap_rep->prepare(q< + SEQUENCE { + msgid INTEGER, + [APPLICATION 4] SEQUENCE { + dn OCTET STRING, + SEQUENCE { + SEQUENCE { + attr OCTET STRING, + SET { + val OCTET STRING + } + } + } + } + } + SEQUENCE { + msgid2 INTEGER, + [APPLICATION 5] SEQUENCE { + error_code ENUMERATED, + matched_dn OCTET STRING, + error_message OCTET STRING + } + } + >); + + my $asn1_rep = $asn_cldap_rep->decode($pdu_out) || die "failed to decode pdu: $@"; + + $$return_string = $asn1_rep->{'val'}; + + return $ret; +} + +sub parse_cldap_reply ($) { + + my $str = shift || return undef; + my %hash; + my $p = 0; + + $hash{type} = unpack("L", substr($str, $p, 4)); $p += 4; + $hash{flags} = unpack("L", substr($str, $p, 4)); $p += 4; + $hash{guid} = unpack("a16", substr($str, $p, 16)); $p += 16; + + $p += pull_netlogon_string($hash{forest}, $p, $str); + $p += pull_netlogon_string($hash{domain}, $p, $str); + $p += pull_netlogon_string($hash{hostname}, $p, $str); + $p += pull_netlogon_string($hash{netbios_domain}, $p, $str); + $p += pull_netlogon_string($hash{netbios_hostname}, $p, $str); + $p += pull_netlogon_string($hash{unk}, $p, $str); + + if ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_R}) { + $p += pull_netlogon_string($hash{user_name}, $p, $str); + } else { + $hash{user_name} = ""; + } + + $p += pull_netlogon_string($hash{server_site_name}, $p, $str); + $p += pull_netlogon_string($hash{client_site_name}, $p, $str); + + $hash{version} = unpack("L", substr($str, $p, 4)); $p += 4; + $hash{lmnt_token} = unpack("S", substr($str, $p, 2)); $p += 2; + $hash{lm20_token} = unpack("S", substr($str, $p, 2)); $p += 2; + + return %hash; +} + +sub display_cldap_reply { + + my $server = shift; + my (%hash) = @_; + + my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($server); + + printf("Information for Domain Controller: %s\n\n", $name); + + printf("Response Type: "); + if ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_R}) { + printf("SAMLOGON_USER\n"); + } elsif ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_UNK_R}) { + printf("SAMLOGON\n"); + } else { + printf("unknown type 0x%x, please report\n", $hash{type}); + } + + # guid + printf("GUID: %s\n", guid_to_string($hash{guid})); + + # flags + dump_cldap_flags($hash{flags}); + + # strings + printf("Forest:\t\t\t%s\n", $hash{forest}); + printf("Domain:\t\t\t%s\n", $hash{domain}); + printf("Domain Controller:\t%s\n", $hash{hostname}); + + printf("Pre-Win2k Domain:\t%s\n", $hash{netbios_domain}); + printf("Pre-Win2k Hostname:\t%s\n", $hash{netbios_hostname}); + + if ($hash{unk}) { + printf("Unk:\t\t\t%s\n", $hash{unk}); + } + if ($hash{user_name}) { + printf("User name:\t%s\n", $hash{user_name}); + } + + printf("Server Site Name:\t%s\n", $hash{server_site_name}); + printf("Client Site Name:\t%s\n", $hash{client_site_name}); + + # some more int + printf("NT Version:\t\t%d\n", $hash{version}); + printf("LMNT Token:\t\t%.2x\n", $hash{lmnt_token}); + printf("LM20 Token:\t\t%.2x\n", $hash{lm20_token}); +} + +sub main() { + + my ($ret, $sock, $reply); + + GetOptions( + 'debug' => \$opt_debug, + 'domain|d=s' => \$opt_domain, + 'help' => \$opt_help, + 'host|h=s' => \$opt_host, + 'server|s=s' => \$opt_server, + ); + + $server = $server || $opt_server; + $domain = $domain || $opt_domain || undef; + $host = $host || $opt_host; + if (!$host) { + $host = `/bin/hostname`; + chomp($host); + } + + if (!$server || !$host || $opt_help) { + usage(); + exit 1; + } + + my $ntver = sprintf("%c%c%c%c", 6,0,0,0); + + $sock = connect_cldap($server); + if (!$sock) { + die("could not connect to $server"); + } + + $ret = send_cldap_netlogon($sock, $domain, $host, $ntver); + if (!$ret) { + close($sock); + die("failed to send CLDAP request to $server"); + } + + $ret = recv_cldap_netlogon($sock, $reply); + if (!$ret) { + close($sock); + die("failed to receive CLDAP reply from $server"); + } + close($sock); + + %cldap_netlogon_reply = parse_cldap_reply($reply); + if (!%cldap_netlogon_reply) { + die("failed to parse CLDAP reply from $server"); + } + + display_cldap_reply($server, %cldap_netlogon_reply); + + exit 0; +} + +main(); -- cgit From dbf7a692edba88e0d609142f1ed11445bc7e841a Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 1 Feb 2007 12:20:33 +0000 Subject: r21105: Quick fix for CLDAP reply without NetLogon attribute. Guenther (This used to be commit aa135c960e5d713daa4ee13a955dc502d12f4f87) --- examples/misc/cldap.pl | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/cldap.pl b/examples/misc/cldap.pl index 2218537f08..c33fdedfbf 100755 --- a/examples/misc/cldap.pl +++ b/examples/misc/cldap.pl @@ -136,7 +136,9 @@ sub send_cldap_netlogon ($$$$) { ) || die "failed to encode pdu: $@"; if ($opt_debug) { + print"------------\n"; asn_dump($pdu_req); + print"------------\n"; } return $sock->send($pdu_req) || die "no send: $@"; @@ -290,10 +292,13 @@ sub recv_cldap_netlogon ($\$) { #$ret = sysread($sock, $pdu_out, 8192); if ($opt_debug) { + print"------------\n"; asn_dump($pdu_out); + print"------------\n"; } my $asn_cldap_rep = Convert::ASN1->new; + my $asn_cldap_rep_fail = Convert::ASN1->new; $asn_cldap_rep->prepare(q< SEQUENCE { @@ -320,9 +325,24 @@ sub recv_cldap_netlogon ($\$) { } >); - my $asn1_rep = $asn_cldap_rep->decode($pdu_out) || die "failed to decode pdu: $@"; + $asn_cldap_rep_fail->prepare(q< + SEQUENCE { + msgid2 INTEGER, + [APPLICATION 5] SEQUENCE { + error_code ENUMERATED, + matched_dn OCTET STRING, + error_message OCTET STRING + } + } + >); - $$return_string = $asn1_rep->{'val'}; + my $asn1_rep = $asn_cldap_rep->decode($pdu_out) || + $asn_cldap_rep_fail->decode($pdu_out) || + die "failed to decode pdu: $@"; + + if ($asn1_rep->{'error_code'} == 0) { + $$return_string = $asn1_rep->{'val'}; + } return $ret; } @@ -453,6 +473,11 @@ sub main() { } close($sock); + if (!$reply) { + printf("no 'NetLogon' attribute received\n"); + exit 0; + } + %cldap_netlogon_reply = parse_cldap_reply($reply); if (!%cldap_netlogon_reply) { die("failed to parse CLDAP reply from $server"); -- cgit From 2d675293d9356099b334b9d1159fcbf4e76624ac Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Wed, 14 Feb 2007 16:20:38 +0000 Subject: r21345: Smaller fixes for adssearch: * get rid of horrible ads.h parsing * add LDAP_SERVER_SHUTDOWN_NOTIFY_OID * display hex bitmasks Guenther (This used to be commit 97ce4ccea215098f574a40a3192d37910f30c79a) --- examples/misc/adssearch.pl | 123 +++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 49 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index 943a755a12..4482222934 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -3,11 +3,10 @@ # adssearch.pl - query an Active Directory server and # display objects in a human readable format # -# Copyright (C) Guenther Deschner 2003-2005 +# Copyright (C) Guenther Deschner 2003-2007 # # TODO: add range retrieval # write sddl-converter, decode userParameters -# chase referrals # apparently only win2k3 allows simple-binds with machine-accounts. # make sasl support independent from Authen::SASL::Cyrus v >0.11 use strict; @@ -50,7 +49,6 @@ my $nmblookup = "/usr/bin/nmblookup"; my $secrets_tdb = "/etc/samba/secrets.tdb"; my $klist = "/usr/bin/klist"; my $kinit = "/usr/bin/kinit"; -my $ads_h = "/home/gd/ads.h"; my $workgroup = ""; my $machine = ""; my $realm = ""; @@ -148,7 +146,6 @@ my ($sasl_hd, $async_ldap_hd, $sync_ldap_hd); my ($mesg, $usn); my (%entry_store); my $async_search; -my (%ads_atype, %ads_gtype, %ads_grouptype, %ads_uf); # fixed values and vars my $set = "X"; @@ -181,6 +178,7 @@ my %ads_controls = ( "LDAP_SERVER_ASQ_OID" => "1.2.840.113556.1.4.1504", "NONE (Get stats control)" => "1.2.840.113556.1.4.970", "LDAP_SERVER_QUOTA_CONTROL_OID" => "1.2.840.113556.1.4.1852", +"LDAP_SERVER_SHUTDOWN_NOTIFY_OID" => "1.2.840.113556.1.4.1907", ); my %ads_capabilities = ( @@ -347,6 +345,74 @@ my %ads_gpo_default_guids = ( "mist" => "61718096-3D3F-4398-8318-203A48976F9E", ); +my %ads_uf = ( + "UF_SCRIPT" => 0x00000001, + "UF_ACCOUNTDISABLE" => 0x00000002, +# "UF_UNUSED_1" => 0x00000004, + "UF_HOMEDIR_REQUIRED" => 0x00000008, + "UF_LOCKOUT" => 0x00000010, + "UF_PASSWD_NOTREQD" => 0x00000020, + "UF_PASSWD_CANT_CHANGE" => 0x00000040, + "UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED" => 0x00000080, + "UF_TEMP_DUPLICATE_ACCOUNT" => 0x00000100, + "UF_NORMAL_ACCOUNT" => 0x00000200, +# "UF_UNUSED_2" => 0x00000400, + "UF_INTERDOMAIN_TRUST_ACCOUNT" => 0x00000800, + "UF_WORKSTATION_TRUST_ACCOUNT" => 0x00001000, + "UF_SERVER_TRUST_ACCOUNT" => 0x00002000, +# "UF_UNUSED_3" => 0x00004000, +# "UF_UNUSED_4" => 0x00008000, + "UF_DONT_EXPIRE_PASSWD" => 0x00010000, + "UF_MNS_LOGON_ACCOUNT" => 0x00020000, + "UF_SMARTCARD_REQUIRED" => 0x00040000, + "UF_TRUSTED_FOR_DELEGATION" => 0x00080000, + "UF_NOT_DELEGATED" => 0x00100000, + "UF_USE_DES_KEY_ONLY" => 0x00200000, + "UF_DONT_REQUIRE_PREAUTH" => 0x00400000, + "UF_PASSWORD_EXPIRED" => 0x00800000, + "UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION" => 0x01000000, + "UF_NO_AUTH_DATA_REQUIRED" => 0x02000000, +# "UF_UNUSED_8" => 0x04000000, +# "UF_UNUSED_9" => 0x08000000, +# "UF_UNUSED_10" => 0x10000000, +# "UF_UNUSED_11" => 0x20000000, +# "UF_UNUSED_12" => 0x40000000, +# "UF_UNUSED_13" => 0x80000000, +); + +my %ads_grouptype = ( + "GROUP_TYPE_BUILTIN_LOCAL_GROUP" => 0x00000001, + "GROUP_TYPE_ACCOUNT_GROUP" => 0x00000002, + "GROUP_TYPE_RESOURCE_GROUP" => 0x00000004, + "GROUP_TYPE_UNIVERSAL_GROUP" => 0x00000008, + "GROUP_TYPE_APP_BASIC_GROUP" => 0x00000010, + "GROUP_TYPE_APP_QUERY_GROUP" => 0x00000020, + "GROUP_TYPE_SECURITY_ENABLED" => 0x80000000, +); + +my %ads_atype = ( + "ATYPE_NORMAL_ACCOUNT" => 0x30000000, + "ATYPE_WORKSTATION_TRUST" => 0x30000001, + "ATYPE_INTERDOMAIN_TRUST" => 0x30000002, + "ATYPE_SECURITY_GLOBAL_GROUP" => 0x10000000, + "ATYPE_DISTRIBUTION_GLOBAL_GROUP" => 0x10000001, + "ATYPE_DISTRIBUTION_UNIVERSAL_GROUP" => 0x10000001, # ATYPE_DISTRIBUTION_GLOBAL_GROUP + "ATYPE_SECURITY_LOCAL_GROUP" => 0x20000000, + "ATYPE_DISTRIBUTION_LOCAL_GROUP" => 0x20000001, + "ATYPE_ACCOUNT" => 0x30000000, # ATYPE_NORMAL_ACCOUNT + "ATYPE_GLOBAL_GROUP" => 0x10000000, # ATYPE_SECURITY_GLOBAL_GROUP + "ATYPE_LOCAL_GROUP" => 0x20000000, # ATYPE_SECURITY_LOCAL_GROUP +); + +my %ads_gtype = ( + "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP" => 0x80000005, + "GTYPE_SECURITY_DOMAIN_LOCAL_GROUP" => 0x80000004, + "GTYPE_SECURITY_GLOBAL_GROUP" => 0x80000002, + "GTYPE_DISTRIBUTION_GLOBAL_GROUP" => 0x00000002, + "GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP" => 0x00000004, + "GTYPE_DISTRIBUTION_UNIVERSAL_GROUP" => 0x00000008, +); + my %munged_dial = ( "CtxCfgPresent" => \&dump_int, "CtxCfgFlags1" => \&dump_int, @@ -371,9 +437,6 @@ $SIG{__WARN__} = sub { Carp::cluck (shift); }; -# parse ads.h -parse_ads_h(); - # if there is data missing, we try to autodetect with samba-tools (if installed) # this might fill up workgroup, machine, realm get_samba_info(); @@ -899,45 +962,6 @@ sub check_sasl_mech { return 0; } - -sub parse_ads_h { - - -e "$ads_h" || die "cannot open samba3 ads.h ($ads_h): $!"; - open(ADSH,"$ads_h"); - while (my $line = ) { - chomp($line); - if ($line =~ /#define.UF.*0x/) { - my ($tmp, $name, $val) = split(/\s+/,$line); - next if ($name =~ /UNUSED/); -# $ads_uf{$name} = sprintf("%d", hex $val); - $ads_uf{$name} = hex $val; - } - if ($line =~ /#define.GROUP_TYPE.*0x/) { - my ($tmp, $name, $val) = split(/\s+/,$line); - $ads_grouptype{$name} = hex $val; - } - if ($line =~ /#define.ATYPE.*0x/) { - my ($tmp, $name, $val) = split(/\s+/,$line); - $ads_atype{$name} = - (exists $ads_atype{$val}) ? $ads_atype{$val} : hex $val; - } - if ($line =~ /#define.GTYPE.*0x/) { - my ($val, $i); - my ($tmp, $name, @val) = split(/\s+/,$line); - foreach my $tempval (@val) { - if ($tempval =~ /^0x/) { - $val = $tempval; - last; - } - } - next if (!$val); - $ads_gtype{$name} = sprintf("%d", hex $val); - } - - } - close(ADSH); -} - sub store_result ($) { my $entry = shift; @@ -1136,12 +1160,13 @@ sub dump_bitmask { my $mod = shift || die "no mod"; my (%header) = @_; my %tmp; - $tmp{""} = $val; + $tmp{""} = sprintf("%s (0x%08x)", $val, $val); foreach my $key (sort keys %header) { # sort by val ! + my $val_hex = sprintf("0x%08x", $header{$key}); if ($op eq "&") { - $tmp{$key} = ( $val & $header{$key} ) ? $set:$unset; + $tmp{"$key ($val_hex)"} = ( $val & $header{$key} ) ? $set:$unset; } elsif ($op eq "==") { - $tmp{$key} = ( $val == $header{$key} ) ? $set:$unset; + $tmp{"$key ($val_hex)"} = ( $val == $header{$key} ) ? $set:$unset; } else { print "unknown operator: $op\n"; return; -- cgit From 0b86e4030604bfbaca66df9f699a68bbf6db0824 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 14 Jun 2007 09:59:07 +0000 Subject: r23484: When chasing AD referrals make sure to honor the base returned from the server. Guenther (This used to be commit 865bdcacae49299c19d7000242832fa41fdfa9d2) --- examples/misc/adssearch.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index 4482222934..da22c57f7e 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -1781,8 +1781,9 @@ sub main () { if (!$opt_notify && ($async_search->code == LDAP_REFERRAL)) { foreach my $ref ($async_search->referrals) { print "\ngot Referral: [$ref]\n"; + my ($prot, $host, $base) = split(/\/+/, $ref); $async_ldap_hd->unbind(); - $async_ldap_hd = get_ldap_hd($ref, 1); + $async_ldap_hd = get_ldap_hd($host, 1); if (do_bind($async_ldap_hd, $sasl_bind) == -1) { $async_ldap_hd->unbind(); next; -- cgit From f914b363da6fd26e5f28bf2d4278a047f88e9612 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Mon, 9 Jul 2007 13:31:32 +0000 Subject: r23767: Add GTYPE_SECURITY_UNIVERSAL_GROUP to adsearch.pl as well. Guenther (This used to be commit 9535866f6ffda866d644855f44f8b987378c4395) --- examples/misc/adssearch.pl | 1 + 1 file changed, 1 insertion(+) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index da22c57f7e..725140ac60 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -408,6 +408,7 @@ my %ads_gtype = ( "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP" => 0x80000005, "GTYPE_SECURITY_DOMAIN_LOCAL_GROUP" => 0x80000004, "GTYPE_SECURITY_GLOBAL_GROUP" => 0x80000002, + "GTYPE_SECURITY_UNIVERSAL_GROUP" => 0x80000008, "GTYPE_DISTRIBUTION_GLOBAL_GROUP" => 0x00000002, "GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP" => 0x00000004, "GTYPE_DISTRIBUTION_UNIVERSAL_GROUP" => 0x00000008, -- cgit From f406b6677cab2b84095c28ff447dd8730b0f2b71 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Tue, 10 Jul 2007 15:13:13 +0000 Subject: r23817: Dump some more guids in adssearch.pl. Guenther (This used to be commit 3f0ac6a27f03c5115f51d1b0a740f5f8ee0fb793) --- examples/misc/adssearch.pl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index 725140ac60..bf9f75f899 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -487,6 +487,7 @@ if (!$password) { my %attr_handler = ( "Token-Groups-No-GC-Acceptable" => \&dump_sid, #wrong name "accountExpires" => \&dump_nttime, + "attributeSecurityGUID" => \&dump_guid, "badPasswordTime" => \&dump_nttime, "creationTime" => \&dump_nttime, "currentTime" => \&dump_timestr, @@ -528,6 +529,7 @@ my %attr_handler = ( "pwdLastSet" => \&dump_nttime, "pwdProperties" => \&dump_pwdproperties, "sAMAccountType" => \&dump_atype, + "schemaIDGUID" => \&dump_guid, "sDRightsEffective" => \&dump_sdeffective, "securityIdentifier" => \&dump_sid, "serverState" => \&dump_serverstate, -- cgit From b8d696ebf0beb2dd858ffcb99be8589d2641f446 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Tue, 10 Jul 2007 15:14:32 +0000 Subject: r23818: support LDAP_SERVER_SEARCH_OPTIONS_OID in adssearch. Guenther (This used to be commit 0f0200c43cdf3f7ced17e2dffdce7f4a4e8f533f) --- examples/misc/adssearch.pl | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index bf9f75f899..b880366c88 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -77,6 +77,7 @@ my ( $opt_port, $opt_realm, $opt_saslmech, + $opt_search_opt, $opt_scope, $opt_simpleauth, $opt_starttls, @@ -108,6 +109,7 @@ GetOptions( 'saslmech|Y=s' => \$opt_saslmech, 'schema|c' => \$opt_dump_schema, 'scope|s=s' => \$opt_scope, + 'searchopt:i' => \$opt_search_opt, 'simpleauth|x' => \$opt_simpleauth, 'tls|Z' => \$opt_starttls, 'user|U=s' => \$opt_user, @@ -1464,6 +1466,21 @@ sub gen_controls { critical => 'true', value => $opt_display_extendeddn ? $ctl_extended_dn_val : ""); + # setup search options + my $search_opt = Convert::ASN1->new; + $search_opt->prepare( + q< searchopt ::= SEQUENCE { + flags INTEGER + } + > + ); + + my $tmp = $search_opt->encode( flags => $opt_search_opt); + my $ctl_search_opt = Net::LDAP::Control->new( + type => $ads_controls{'LDAP_SERVER_SEARCH_OPTIONS_OID'}, + critical => 'true', + value => $tmp); + # setup notify control my $ctl_notification = Net::LDAP::Control->new( type => $ads_controls{'LDAP_SERVER_NOTIFICATION_OID'}, @@ -1506,6 +1523,11 @@ sub gen_controls { push(@ctrls_s, "LDAP_SERVER_DOMAIN_SCOPE_OID"); } + if ($opt_search_opt) { + push(@ctrls, $ctl_search_opt); + push(@ctrls_s, "LDAP_SERVER_SEARCH_OPTIONS_OID"); + } + return @ctrls; } -- cgit From 47d2f021c80a7d961a211d7b2f8dc899b2f8deca Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Wed, 11 Jul 2007 09:49:10 +0000 Subject: r23827: Fix schema dump. Guenther (This used to be commit e3d6dabcb9786ae81f2736815a3b576a962eef3b) --- examples/misc/adssearch.pl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index b880366c88..a63ae311eb 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -837,7 +837,8 @@ sub get_base_from_rootdse { my $server = shift || ""; $dse = shift || get_dse($server,$async_ldap_hd) || return -1; - return $dse->get_value('defaultNamingContext'); + return $dse->get_value($opt_dump_schema ? 'schemaNamingContext': + 'defaultNamingContext'); } sub get_realm_from_rootdse { @@ -1499,7 +1500,7 @@ sub gen_controls { critical => 'true', value => ""); - if (defined($opt_paging)) { + if (defined($opt_paging) || $opt_dump_schema) { push(@ctrls, $ctl_paged); push(@ctrls_s, "LDAP_PAGED_RESULT_OID_STRING" ); } @@ -1787,9 +1788,9 @@ sub main () { if ($opt_dump_schema) { print "Dumping Schema:\n"; - my $ads_schema = $async_ldap_hd->schema; - $ads_schema->dump; - exit 0; +# my $ads_schema = $async_ldap_hd->schema; +# $ads_schema->dump; +# exit 0; } while (1) { -- cgit From d9a1282cc5e4a44495ec8ce20ef6dad6dc79c96b Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Mon, 28 Jan 2008 19:22:17 +0100 Subject: Dump msDS-SupportedEncryptionTypes in adssearch. Guenther (This used to be commit bc0b68709cbbdd71996a39e23fe8305e1f144f31) --- examples/misc/adssearch.pl | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'examples/misc') diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl index a63ae311eb..d17e680ec8 100755 --- a/examples/misc/adssearch.pl +++ b/examples/misc/adssearch.pl @@ -3,7 +3,7 @@ # adssearch.pl - query an Active Directory server and # display objects in a human readable format # -# Copyright (C) Guenther Deschner 2003-2007 +# Copyright (C) Guenther Deschner 2003-2008 # # TODO: add range retrieval # write sddl-converter, decode userParameters @@ -230,6 +230,7 @@ my %ads_mixed_domain = ( my %ads_ds_func = ( "DS_BEHAVIOR_WIN2000" => 0, # untested "DS_BEHAVIOR_WIN2003" => 2, +"DS_BEHAVIOR_WIN2008" => 3, ); my %ads_instance_type = ( @@ -244,6 +245,14 @@ my %ads_uacc = ( "ACCOUNT_LOCKED_OUT" => 0x800010, # 8388624 ); +my %ads_enctypes = ( + "DES-CBC-CRC" => 0x01, + "DES-CBC-MD5" => 0x02, + "RC4_HMAC_MD5" => 0x04, + "AES128_CTS_HMAC_SHA1_96" => 0x08, + "AES128_CTS_HMAC_SHA1_128" => 0x10, +); + my %ads_gpoptions = ( "GPOPTIONS_INHERIT" => 0, "GPOPTIONS_BLOCK_INHERITANCE" => 1, @@ -518,6 +527,7 @@ my %attr_handler = ( "modifyTimeStamp" => \&dump_timestr, "msDS-Behavior-Version" => \&dump_ds_func, #unsure "msDS-User-Account-Control-Computed" => \&dump_uacc, + "msDS-SupportedEncryptionTypes" => \&dump_enctypes, "mS-DS-CreatorSID" => \&dump_sid, # "msRADIUSFramedIPAddress" => \&dump_ipaddr, # "msRASSavedFramedIPAddress" => \&dump_ipaddr, @@ -1209,6 +1219,10 @@ sub dump_uacc { return dump_bitmask_equal(@_,%ads_uacc); } +sub dump_enctypes { + return dump_bitmask_and(@_,%ads_enctypes); +} + sub dump_uf { return dump_bitmask_and(@_,%ads_uf); } -- cgit