diff options
Diffstat (limited to 'testprogs')
40 files changed, 4427 insertions, 0 deletions
diff --git a/testprogs/blackbox/ndrdump/samr-CreateUser-in.dat b/testprogs/blackbox/ndrdump/samr-CreateUser-in.dat Binary files differnew file mode 100644 index 0000000000..a5840e1f7f --- /dev/null +++ b/testprogs/blackbox/ndrdump/samr-CreateUser-in.dat diff --git a/testprogs/blackbox/ndrdump/samr-CreateUser-out.dat b/testprogs/blackbox/ndrdump/samr-CreateUser-out.dat Binary files differnew file mode 100644 index 0000000000..cf9131dba9 --- /dev/null +++ b/testprogs/blackbox/ndrdump/samr-CreateUser-out.dat diff --git a/testprogs/blackbox/subunit.sh b/testprogs/blackbox/subunit.sh new file mode 100755 index 0000000000..100dfd1a46 --- /dev/null +++ b/testprogs/blackbox/subunit.sh @@ -0,0 +1,67 @@ +# +# subunit.sh: shell functions to report test status via the subunit protocol. +# Copyright (C) 2006 Robert Collins <robertc@robertcollins.net> +# Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +subunit_start_test () { + # emit the current protocol start-marker for test $1 + echo "test: $1" +} + + +subunit_pass_test () { + # emit the current protocol test passed marker for test $1 + echo "success: $1" +} + + +subunit_fail_test () { + # emit the current protocol fail-marker for test $1, and emit stdin as + # the error text. + # we use stdin because the failure message can be arbitrarily long, and this + # makes it convenient to write in scripts (using <<END syntax. + echo "failure: $1 [" + cat - + echo "]" +} + + +subunit_error_test () { + # emit the current protocol error-marker for test $1, and emit stdin as + # the error text. + # we use stdin because the failure message can be arbitrarily long, and this + # makes it convenient to write in scripts (using <<END syntax. + echo "error: $1 [" + cat - + echo "]" +} + +testit () { + name="$1" + shift + cmdline="$*" + subunit_start_test "$name" + output=`$cmdline 2>&1` + status=$? + if [ x$status = x0 ]; then + subunit_pass_test "$name" + else + echo $output | subunit_fail_test "$name" + fi + return $status +} diff --git a/testprogs/blackbox/test_gentest.sh b/testprogs/blackbox/test_gentest.sh new file mode 100755 index 0000000000..ec6f0e422b --- /dev/null +++ b/testprogs/blackbox/test_gentest.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Blackbox tests for gentest +# Copyright (C) 2008 Andrew Tridgell +# based on test_smbclient.sh + +if [ $# -lt 4 ]; then +cat <<EOF +Usage: test_gentest.sh SERVER USERNAME PASSWORD DOMAIN +EOF +exit 1; +fi + +SERVER=$1 +USERNAME=$2 +PASSWORD=$3 +DOMAIN=$4 +shift 4 +failed=0 + +samba4bindir=`dirname $0`/../../source/bin +gentest=$samba4bindir/gentest + +. `dirname $0`/subunit.sh + +cat <<EOF > st/gentest.ignore +all_info.out.fname +internal_information.out.file_id +EOF + +testit "gentest" $VALGRIND $gentest //$SERVER/test1 //$SERVER/test2 --num-ops=100 --ignore=st/gentest.ignore -W "$DOMAIN" -U"$USERNAME%$PASSWORD" -U"$USERNAME%$PASSWORD" $@ || failed=`expr $failed + 1` + +/bin/rm -f st/gentest.ignore + +exit $failed diff --git a/testprogs/blackbox/test_kinit.sh b/testprogs/blackbox/test_kinit.sh new file mode 100755 index 0000000000..d3cece0af7 --- /dev/null +++ b/testprogs/blackbox/test_kinit.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# Blackbox tests for kinit and kerberos integration with smbclient etc +# Copyright (C) 2006-2007 Jelmer Vernooij <jelmer@samba.org> +# Copyright (C) 2006-2007 Andrew Bartlett <abartlet@samba.org> + +if [ $# -lt 5 ]; then +cat <<EOF +Usage: test_kinit.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX +EOF +exit 1; +fi + +SERVER=$1 +USERNAME=$2 +PASSWORD=$3 +REALM=$4 +DOMAIN=$5 +PREFIX=$6 +shift 6 +failed=0 + +samba4bindir=`dirname $0`/../../source/bin +smbclient=$samba4bindir/smbclient +samba4kinit=$samba4bindir/samba4kinit +net=$samba4bindir/net +enableaccount="$PYTHON `dirname $0`/../../source/setup/enableaccount" + +. `dirname $0`/subunit.sh + +test_smbclient() { + name="$1" + cmd="$2" + shift + shift + echo "test: $name" + $VALGRIND $smbclient $CONFIGURATION //$SERVER/tmp -c "$cmd" -W "$DOMAIN" -U"$USERNAME%$PASSWORD" $@ + status=$? + if [ x$status = x0 ]; then + echo "success: $name" + else + echo "failure: $name" + fi + return $status +} + +KRB5CCNAME="$PREFIX/tmpccache" +export KRB5CCNAME + +echo $PASSWORD > ./tmppassfile +#testit "kinit with keytab" $samba4kinit --keytab=$PREFIX/dc/private/secrets.keytab $SERVER\$@$REALM || failed=`expr $failed + 1` +testit "kinit with password" $samba4kinit --password-file=./tmppassfile --request-pac $USERNAME@$REALM || failed=`expr $failed + 1` +testit "kinit with pkinit" $samba4kinit --request-pac --renewable --pk-user=FILE:$PREFIX/dc/private/tls/admincert.pem,$PREFIX/dc/private/tls/adminkey.pem $USERNAME@$REALM || failed=`expr $failed + 1` +testit "kinit renew ticket" $samba4kinit --request-pac -R + +test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1` + +testit "domain join with kerberos ccache" $VALGRIND $net join $DOMAIN $CONFIGURATION -W "$DOMAIN" -k yes $@ || failed=`expr $failed + 1` +testit "check time with kerberos ccache" $VALGRIND $net time $SERVER $CONFIGURATION -W "$DOMAIN" -k yes $@ || failed=`expr $failed + 1` + +testit "add user with kerberos ccache" $VALGRIND $net user add nettestuser $CONFIGURATION -k yes $@ || failed=`expr $failed + 1` +USERPASS=testPass@12% +echo $USERPASS > ./tmpuserpassfile + +testit "set user password with kerberos ccache" $VALGRIND $net password set $DOMAIN\\nettestuser $USERPASS $CONFIGURATION -k yes $@ || failed=`expr $failed + 1` + +testit "enable user with kerberos cache" $VALGRIND $enableaccount nettestuser -H ldap://$SERVER -k yes $@ || failed=`expr $failed + 1` + +KRB5CCNAME="$PREFIX/tmpuserccache" +export KRB5CCNAME + +testit "kinit with user password" $samba4bindir/samba4kinit --password-file=./tmpuserpassfile --request-pac nettestuser@$REALM || failed=`expr $failed + 1` + +test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1` + +NEWUSERPASS=testPaSS@34% +testit "change user password" $VALGRIND $net password change -W$DOMAIN -U$DOMAIN\\nettestuser%$USERPASS $CONFIGURATION -k no $NEWUSERPASS $@ || failed=`expr $failed + 1` + +echo $NEWUSERPASS > ./tmpuserpassfile +testit "kinit with user password" $samba4bindir/samba4kinit --password-file=./tmpuserpassfile --request-pac nettestuser@$REALM || failed=`expr $failed + 1` + +test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1` + +KRB5CCNAME="$PREFIX/tmpccache" +export KRB5CCNAME + +testit "del user with kerberos ccache" $VALGRIND $net user delete nettestuser $CONFIGURATION -k yes $@ || failed=`expr $failed + 1` + +rm -f tmpccfile tmppassfile tmpuserpassfile tmpuserccache +exit $failed diff --git a/testprogs/blackbox/test_ldb.sh b/testprogs/blackbox/test_ldb.sh new file mode 100755 index 0000000000..8e1af99719 --- /dev/null +++ b/testprogs/blackbox/test_ldb.sh @@ -0,0 +1,121 @@ +#!/bin/sh + +if [ $# -lt 2 ]; then +cat <<EOF +Usage: test_ldb.sh PROTOCOL SERVER [OPTIONS] +EOF +exit 1; +fi + + +p=$1 +SERVER=$2 +PREFIX=$3 +shift 2 +options="$*" + +. `dirname $0`/subunit.sh + +check() { + name="$1" + shift + cmdline="$*" + echo "test: $name" + $cmdline + status=$? + if [ x$status = x0 ]; then + echo "success: $name" + else + echo "failure: $name" + failed=`expr $failed + 1` + fi + return $status +} + +check "RootDSE" bin/ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base DUMMY=x dnsHostName highestCommittedUSN || failed=`expr $failed + 1` + +echo "Getting defaultNamingContext" +BASEDN=`bin/ldbsearch $CONFIGURATION $options --basedn='' -H $p://$SERVER -s base DUMMY=x defaultNamingContext | grep defaultNamingContext | awk '{print $2}'` +echo "BASEDN is $BASEDN" + +check "Listing Users" bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER '(objectclass=user)' sAMAccountName || failed=`expr $failed + 1` + +check "Listing Users (sorted)" bin/ldbsearch -S $options $CONFIGURATION -H $p://$SERVER '(objectclass=user)' sAMAccountName || failed=`expr $failed + 1` + +check "Listing Groups" bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER '(objectclass=group)' sAMAccountName || failed=`expr $failed + 1` + +nentries=`bin/ldbsearch $options -H $p://$SERVER $CONFIGURATION '(|(|(&(!(groupType:1.2.840.113556.1.4.803:=1))(groupType:1.2.840.113556.1.4.803:=2147483648)(groupType:1.2.840.113556.1.4.804:=10))(samAccountType=805306368))(samAccountType=805306369))' sAMAccountName | grep sAMAccountName | wc -l` +echo "Found $nentries entries" +if [ $nentries -lt 10 ]; then +echo "Should have found at least 10 entries" +failed=`expr $failed + 1` +fi + +echo "Check rootDSE for Controls" +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER -s base -b "" '(objectclass=*)' | grep -i supportedControl | wc -l` +if [ $nentries -lt 4 ]; then +echo "Should have found at least 4 entries" +failed=`expr $failed + 1` +fi + +echo "Test Paged Results Control" +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=paged_results:1:5 '(objectclass=user)' | grep sAMAccountName | wc -l` +if [ $nentries -lt 1 ]; then +echo "Paged Results Control test returned 0 items" +failed=`expr $failed + 1` +fi + +echo "Test Server Sort Control" +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=server_sort:1:0:sAMAccountName '(objectclass=user)' | grep sAMAccountName | wc -l` +if [ $nentries -lt 1 ]; then +echo "Server Sort Control test returned 0 items" +failed=`expr $failed + 1` +fi + +echo "Test Extended DN Control" +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=extended_dn:1 '(objectclass=user)' | grep sAMAccountName | wc -l` +if [ $nentries -lt 1 ]; then +echo "Extended DN Control test returned 0 items" +failed=`expr $failed + 1` +fi +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=extended_dn:1:0 '(objectclass=user)' | grep sAMAccountName | wc -l` +if [ $nentries -lt 1 ]; then +echo "Extended DN Control test returned 0 items" +failed=`expr $failed + 1` +fi +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=extended_dn:1:1 '(objectclass=user)' | grep sAMAccountName | wc -l` +if [ $nentries -lt 1 ]; then +echo "Extended DN Control test returned 0 items" +failed=`expr $failed + 1` +fi + +echo "Test Domain scope Control" +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=domain_scope:1 '(objectclass=user)' | grep sAMAccountName | wc -l` +if [ $nentries -lt 1 ]; then +echo "Extended Domain scope Control test returned 0 items" +failed=`expr $failed + 1` +fi + +echo "Test Attribute Scope Query Control" +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=asq:1:member -s base -b "CN=Administrators,CN=Builtin,$BASEDN" | grep sAMAccountName | wc -l` +if [ $nentries -lt 1 ]; then +echo "Attribute Scope Query test returned 0 items" +failed=`expr $failed + 1` +fi + +echo "Test Search Options Control" +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=search_options:1:2 '(objectclass=crossRef)' | grep crossRef | wc -l` +if [ $nentries -lt 1 ]; then +echo "Search Options Control Query test returned 0 items" +failed=`expr $failed + 1` +fi + +echo "Test Search Options Control with Domain Scope Control" +nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER --controls=search_options:1:2,domain_scope:1 '(objectclass=crossRef)' | grep crossRef | wc -l` +if [ $nentries -lt 1 ]; then +echo "Search Options Control Query test returned 0 items" +failed=`expr $failed + 1` +fi + + +exit $failed diff --git a/testprogs/blackbox/test_locktest.sh b/testprogs/blackbox/test_locktest.sh new file mode 100755 index 0000000000..88fa0ef892 --- /dev/null +++ b/testprogs/blackbox/test_locktest.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# Blackbox tests for locktest +# Copyright (C) 2008 Andrew Tridgell +# based on test_smbclient.sh + +if [ $# -lt 5 ]; then +cat <<EOF +Usage: test_locktest.sh SERVER USERNAME PASSWORD DOMAIN PREFIX +EOF +exit 1; +fi + +SERVER=$1 +USERNAME=$2 +PASSWORD=$3 +DOMAIN=$4 +PREFIX=$5 +shift 5 +failed=0 + +samba4bindir=`dirname $0`/../../source/bin +locktest=$samba4bindir/locktest + +. `dirname $0`/subunit.sh + +testit "locktest" $VALGRIND $locktest //$SERVER/test1 //$SERVER/test2 --num-ops=100 -W "$DOMAIN" -U"$USERNAME%$PASSWORD" $@ || failed=`expr $failed + 1` + +exit $failed diff --git a/testprogs/blackbox/test_masktest.sh b/testprogs/blackbox/test_masktest.sh new file mode 100755 index 0000000000..c1f765c1dd --- /dev/null +++ b/testprogs/blackbox/test_masktest.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# Blackbox tests for masktest +# Copyright (C) 2008 Andrew Tridgell +# based on test_smbclient.sh + +if [ $# -lt 5 ]; then +cat <<EOF +Usage: test_masktest.sh SERVER USERNAME PASSWORD DOMAIN PREFIX +EOF +exit 1; +fi + +SERVER=$1 +USERNAME=$2 +PASSWORD=$3 +DOMAIN=$4 +PREFIX=$5 +shift 5 +failed=0 + +samba4bindir=`dirname $0`/../../source/bin +masktest=$samba4bindir/masktest + +. `dirname $0`/subunit.sh + +testit "masktest" $VALGRIND $masktest //$SERVER/tmp --num-ops=200 --dieonerror -W "$DOMAIN" -U"$USERNAME%$PASSWORD" $@ || failed=`expr $failed + 1` + +exit $failed diff --git a/testprogs/blackbox/test_ndrdump.sh b/testprogs/blackbox/test_ndrdump.sh new file mode 100755 index 0000000000..089a7c3a2b --- /dev/null +++ b/testprogs/blackbox/test_ndrdump.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# Blackbox tests for masktest +# Copyright (C) 2008 Andrew Tridgell +# Copyright (C) 2008 Andrew Bartlett +# based on test_smbclient.sh + +. `dirname $0`/subunit.sh + +failed=0 + +samba4bindir=`dirname $0`/../../source/bin +ndrdump=$samba4bindir/ndrdump +files=`dirname $0`/ndrdump + +testit "ndrdump with in" $VALGRIND $ndrdump samr samr_CreateUser in $files/samr-CreateUser-in.dat $@ || failed=`expr $failed + 1` +testit "ndrdump with out" $VALGRIND $ndrdump samr samr_CreateUser out $files/samr-CreateUser-out.dat $@ || failed=`expr $failed + 1` +testit "ndrdump with --context-file" $VALGRIND $ndrdump --context-file $files/samr-CreateUser-in.dat samr samr_CreateUser out $files/samr-CreateUser-out.dat $@ || failed=`expr $failed + 1` +testit "ndrdump with validate" $VALGRIND $ndrdump --validate samr samr_CreateUser in $files/samr-CreateUser-in.dat $@ || failed=`expr $failed + 1` + +exit $failed diff --git a/testprogs/blackbox/test_wintest.sh b/testprogs/blackbox/test_wintest.sh new file mode 100755 index 0000000000..8bbe4f2984 --- /dev/null +++ b/testprogs/blackbox/test_wintest.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Blackbox tests for testing against windows machines +# Copyright (C) 2008 Jim McDonough + + +testwithconf() { +# define test variables, startup/shutdown scripts +. $1 +shift 1 + +if [ -n "$WINTEST_STARTUP" ]; then +. $WINTEST_STARTUP; +fi + +testit "smbtorture" $smbtorture //$SERVER/$SHARE RAW-OPEN -W "$DOMAIN" -U"$USERNAME%$PASSWORD" $@ || failed=`expr $failed + 1` + +if [ -n "$WINTEST_SHUTDOWN" ]; then +. $WINTEST_SHUTDOWN; +fi +} + + +# main +# skip without WINTEST_CONF_DIR +if [ -z "$WINTEST_CONF_DIR" ]; then +exit 0; +fi + +SOCKET_WRAPPER_DIR= +export -n SOCKET_WRAPPER_DIR + +failed=0 + +$basedir=`pwd` + +samba4bindir=`dirname $0`/../../source/bin +smbtorture=$samba4bindir/smbtorture + +. `dirname $0`/subunit.sh + +for wintest_conf in $WINTEST_CONF_DIR/*.conf; do +testwithconf "$wintest_conf" $@; +done + +exit $failed diff --git a/testprogs/blackbox/wintest/wintest.conf b/testprogs/blackbox/wintest/wintest.conf new file mode 100644 index 0000000000..d1403662f9 --- /dev/null +++ b/testprogs/blackbox/wintest/wintest.conf @@ -0,0 +1,7 @@ +#export WINTEST_STARTUP="/tmp/startup client" +#export WINTEST_SHUTDOWN=/tmp/shutdown client" +export DOMAIN="client" +export USERNAME="administrator" +export PASSWORD="samba" +export SERVER="192.168.213.161" +export SHARE="c\$"
\ No newline at end of file diff --git a/testprogs/ejs/base.js b/testprogs/ejs/base.js new file mode 100755 index 0000000000..3c998ee4f8 --- /dev/null +++ b/testprogs/ejs/base.js @@ -0,0 +1,23 @@ +#!/bin/sh +exec smbscript "$0" ${1+"$@"} + +var options = GetOptions(ARGV, + "POPT_COMMON_SAMBA"); +if (options == undefined) { + println("Failed to parse options"); + return -1; +} + +libinclude("base.js"); + +var obj = new Object(); +obj.FOO = "foo"; +obj.BAR = "bar"; +var str1 = "${FOO}:${BAR}"; +var str2 = "${FOO}:${BAR} "; // note the space after the brace +var sub1 = substitute_var(str1, obj); +var sub2 = substitute_var(str2, obj); + +assert(str1 + " " == str2); +assert(sub1 + " " == sub2); +exit(0); diff --git a/testprogs/ejs/bugs.js b/testprogs/ejs/bugs.js new file mode 100644 index 0000000000..0c1cecb486 --- /dev/null +++ b/testprogs/ejs/bugs.js @@ -0,0 +1,155 @@ +/* + demonstrate some bugs in ejs + + tridge <appweb@tridgell.net> +*/ + + +/**************************************** +demo a bug in constructing arrays +fix at http://build.samba.org/build.pl?function=diff;tree=samba4;revision=7124 +status: FIXED +*****************************************/ +function arraybug() { + var a; + + println("First with 3 elements"); + a = new Array("one", "two", "three"); + printVars(a); + assert(a.length == 3); + assert(a[0] == "one"); + assert(a[1] == "two"); + assert(a[2] == "three"); + + println("with a array length"); + a = new Array(5); + printVars(a); + assert(a.length == 5); + + println("\nNow with 1 element"); + a = new Array("one"); + printVars(a); + assert(a.length == 1); + assert(a[0] == "one"); + + println("ALL OK"); +} + + +/**************************************** +demo a bug in variable arguments +fix at http://build.samba.org/build.pl?function=diff;tree=samba4;revision=7085 +status: FIXED +*****************************************/ +function argsbug() { + println("we should have been called with 3 arguments"); + assert(arguments.length == 3); + assert(arguments[0] == "one"); + assert(arguments[1] == "two"); + assert(arguments[2] == "three"); +} + + +/**************************************** +demo a bug in constructing objects +no fix available yet +status: SUBMITTED +*****************************************/ +function MyObj() { + var o = new Object(); + o.test = 42; + return o; +} + +function objbug() { + println("the docs say you should use 'new'"); + var o1 = new MyObj(); + var o2 = MyObj(); + printVars(o1); + printVars(o2); + assert(o1.test == 42); + assert(o2.test == 42); +} + +/* + demo a expression handling bug + status: FIXED +*/ +function exprbug() { + var a = new Array(10); + var i; + for (i=0;i<4;i++) { + a[1+(i*2)] = i; + a[2+(i*2)] = i*2; + } +} + +/**************************************** +demo lack of recursion +fix in http://build.samba.org/build.pl?function=diff;tree=samba4;revision=7127 +status: FIXED +*****************************************/ +function fibonacci(n) { + if (n < 3) { + return 1; + } + return fibonacci(n-1) + fibonacci(n-2); +} + +function recursebug() { + println("First 10 fibonacci numbers:"); + for (i=0;i<10;i++) { + println("fibonacci(" + i + ")=" + fibonacci(i)); + } +} + +/**************************************** +demo lack of function variables inside functions +status: FIXED IN SAMBA +*****************************************/ +function callback() +{ + return "testing"; +} + +function fnbug(c) +{ + s = c(); + assert(s == "testing"); +} + +/**************************************** +demo incorrect handling of reserved words in strings +status: SUBMITTED +*****************************************/ +function reservedbug() +{ + assert("funct" + "ion" == 'function'); +} + + +/**************************************** +demo incorrect handling of boolean functions +status: SUBMITTED +*****************************************/ +function no() +{ + return false; +} + +function boolbug() +{ + assert(false == no()); + assert(!no()); +} + + +/* run the tests */ +arraybug(); +argsbug("one", "two", "three"); +recursebug(); +exprbug(); +fnbug(callback); +reservedbug(); +boolbug(); +objbug(); diff --git a/testprogs/ejs/ldb.js b/testprogs/ejs/ldb.js new file mode 100755 index 0000000000..8c71994805 --- /dev/null +++ b/testprogs/ejs/ldb.js @@ -0,0 +1,385 @@ +#!/bin/sh +exec smbscript "$0" ${1+"$@"} +/* + demonstrate access to ldb databases from ejs +*/ + + +var ldb = ldb_init(); +var sys; +var options = GetOptions(ARGV, + "POPT_AUTOHELP", + "POPT_COMMON_SAMBA"); +if (options == undefined) { + println("Failed to parse options"); + return -1; +} + +libinclude("base.js"); + +if (options.ARGV.length != 1) { + println("Usage: ldb.js <prefix>"); + return -1; +} + +prefix = options.ARGV[0]; + +function basic_tests(ldb) +{ + println("Running basic tests"); + ok = ldb.add(" +dn: cn=x,cn=test +objectClass: foo +x: 3 +"); + assert(ok.error == 0); + + println("Testing ldb.search"); + var res = ldb.search("(objectClass=*)"); + assert(res.msgs[0].objectClass[0] == "foo"); + assert(res.msgs[0].dn == "cn=x,cn=test"); + assert(res.msgs[0].x == 3); + + ok = ldb.add(" +dn: cn=x2,cn=test +objectClass: foo +x: 4 +"); + assert(ok.error == 0); + var attrs = new Array("x"); + res = ldb.search("x=4", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.msgs[0].x == 4); + assert(res.msgs[0].objectClass == undefined); + assert(res.msgs[0].dn == "cn=x2,cn=test"); + + ok = ldb.del("cn=x,cn=test"); + assert(ok.error == 0); + + ok = ldb.rename("cn=x2,cn=test", "cn=x3,cn=test"); + assert(ok.error == 0); + res = ldb.search("x=4", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.msgs[0].dn == "cn=x3,cn=test"); + + ok = ldb.rename("cn=x3,cn=test", "cn=X3,cn=test"); + assert(ok.error == 0); + res = ldb.search("x=4", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.msgs[0].dn == "cn=X3,cn=test"); + + ok = ldb.modify(" +dn: cn=x3,cn=test +changetype: modify +add: x +x: 7 +"); + + res = ldb.search("x=7"); + assert(res.msgs.length == 1); + assert(res.msgs[0].x.length == 2); + + /* Check a few things before we add modules */ + assert(res.msgs[0].objectGUID == undefined); + assert(res.msgs[0].createTimestamp == undefined); + assert(res.msgs[0].whenCreated == undefined); + +} + +function setup_modules(ldb) +{ + ok = ldb.add(" +dn: @MODULES +@LIST: rootdse,operational,rdn_name,partition + +dn: @ROOTDSE +defaultNamingContext: cn=Test + +dn: @PARTITION +partition: cn=SideTest:" + prefix + "/" + "testside.ldb +partition: cn=Sub,cn=PartTest:" + prefix + "/" + "testsub.ldb +partition: cn=PartTest:" + prefix + "/" + "testpartition.ldb +partition: cn=Sub,cn=Sub,cn=PartTest:" + prefix + "/" + "testsubsub.ldb +replicateEntries: @ATTRIBUTES +replicateEntries: @INDEXLIST +modules: cn=PartTest:objectguid +"); +} + +/* Test the basic operation of the timestamps,objectguid and name_rdn + modules */ + +function modules_test(ldb, parttestldb) +{ + println("Running modules tests"); + + ok = ldb.add(" +dn: @ATTRIBUTES +cn: CASE_INSENSITIVE +caseattr: CASE_INSENSITIVE +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + /* Confirm that the attributes were replicated */ + var res_attrs = parttestldb.search("cn=*", "@ATTRIBUTES", parttestldb.SCOPE_BASE); + assert(res_attrs.msgs[0].cn == "CASE_INSENSITIVE"); + + ok = ldb.add(" +dn: cn=x8,cn=PartTest +objectClass: foo +x: 8 +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + ok = ldb.add(" +dn: cn=x9,cn=PartTest +objectClass: foo +x: 9 +cn: X9 +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + ok = ldb.add(" +dn: cn=X9,cn=PartTest +objectClass: foo +x: 9 +cn: X9 +"); + if (ok.error == 0) { + println("Should have failed to add cn=X9,cn=PartTest"); + assert(ok.error != 0); + } + + var res = ldb.search("x=8", "cn=PartTest", ldb.SCOPE_DEFAULT); + assert(res.msgs[0].objectGUID != undefined); + assert(res.msgs[0].uSNCreated != undefined); + assert(res.msgs[0].uSNChanged != undefined); + assert(res.msgs[0].createTimestamp == undefined); + assert(res.msgs[0].whenCreated != undefined); + assert(res.msgs[0].name == "x8"); + assert(res.msgs[0].cn == "x8"); + + /* Confirm that this ended up in the correct LDB */ + var res_otherldb = parttestldb.search("x=8", "cn=PartTest", parttestldb.SCOPE_DEFAULT); + assert(res_otherldb.msgs[0].objectGUID != undefined); + assert(res_otherldb.msgs[0].createTimestamp == undefined); + assert(res_otherldb.msgs[0].whenCreated != undefined); + assert(res_otherldb.msgs[0].name == "x8"); + assert(res_otherldb.msgs[0].cn == "x8"); + + var attrs = new Array("*", "createTimestamp"); + var res2 = ldb.search("x=9", "cn=PartTest", ldb.SCOPE_DEFAULT, attrs); + assert(res2.msgs[0].objectGUID != undefined); + assert(res2.msgs[0].createTimestamp != undefined); + assert(res2.msgs[0].whenCreated != undefined); + assert(res2.msgs[0].name == "x9"); + assert(res2.msgs[0].cn == "x9"); + + assert(res.msgs[0].objectGUID != res2.msgs[0].objectGUID); + + var attrs = new Array("*"); + var res3 = ldb.search("", "", ldb.SCOPE_BASE, attrs); + assert(res3.msgs[0].cn == undefined); + assert(res3.msgs[0].distinguishedName == undefined); + assert(res3.msgs[0].name == undefined); + assert(res3.msgs[0].currentTime != undefined); + assert(res3.msgs[0].highestCommittedUSN != undefined); + + assert(res3.msgs[0].namingContexts[0] == "cn=Sub,cn=Sub,cn=PartTest"); + assert(res3.msgs[0].namingContexts[1] == "cn=Sub,cn=PartTest"); + assert(res3.msgs[0].namingContexts[2] == "cn=PartTest"); + assert(res3.msgs[0].namingContexts[3] == "cn=SideTest"); + var usn = res3.msgs[0].highestCommittedUSN; + + /* Start a transaction. We are going to abort it later, to + * show we clean up all partitions */ + + ok = ldb.transaction_start() + if (!ok) { + println("Failed to start a transaction: " + ok.errstr); + assert(ok.error == 0); + } + + + ok = ldb.add(" +dn: cn=x10,cn=parttest +objectClass: foo +x: 10 +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + var attrs = new Array("highestCommittedUSN"); + var res4 = ldb.search("", "", ldb.SCOPE_BASE, attrs); + var usn2 = res4.msgs[0].highestCommittedUSN; + assert(usn < res4.msgs[0].highestCommittedUSN); + + ok = ldb.add(" +dn: cn=x11,cn=sub,cn=parttest +objectClass: foo +x: 11 +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + var attrs = new Array("highestCommittedUSN"); + var res5 = ldb.search("", "", ldb.SCOPE_BASE, attrs); + assert(usn2 < res5.msgs[0].highestCommittedUSN); + + var attrs = new Array("*", "createTimestamp"); + var res6 = ldb.search("x=11", "cn=parttest", ldb.SCOPE_SUB, attrs); + assert(res6.msgs.length == 0); + + var attrs = new Array("*", "createTimestamp"); + var res7 = ldb.search("x=10", "cn=sub,cn=parttest", ldb.SCOPE_DEFAULT, attrs); + assert(res7.msgs.length == 0); + + var res8 = ldb.search("x=11", "cn=sub,cn=parttest", ldb.SCOPE_DEFAULT, attrs); + + assert(res8.msgs[0].objectGUID == undefined); /* The objectGUID module is not loaded here */ + assert(res8.msgs[0].uSNCreated == undefined); /* The objectGUID module is not loaded here */ + assert(res8.msgs[0].name == "x11"); + assert(res8.msgs[0].cn == "x11"); + + ok = ldb.add(" +dn: caseattr=XY,cn=PartTest +objectClass: foo +x: Y +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + ok = ldb.add(" +dn: caseattr=XZ,cn=PartTest +objectClass: foo +x: Z +caseattr: XZ +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + ok = ldb.add(" +dn: caseattr=xz,cn=PartTest +objectClass: foo +x: Z +caseattr: xz +"); + if (ok.error == 0) { + println("Should have failed to add caseattr=xz,cn=PartTest"); + assert(ok.error != 0); + } + + ok = ldb.add(" +dn: caseattr2=XZ,cn=PartTest +objectClass: foo +x: Z +caseattr2: XZ +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + ok = ldb.add(" +dn: caseattr2=Xz,cn=PartTest +objectClass: foo +x: Z +caseattr2: Xz +"); + if (ok.error != 0) { + println("Failed to add: " + ok.errstr); + assert(ok.error == 0); + } + + var resX = ldb.search("caseattr=xz", "cn=parttest", ldb.SCOPE_DEFAULT, attrs); + assert(resX.msgs.length == 1); + assert(resX.msgs[0].objectGUID != undefined); + assert(resX.msgs[0].createTimestamp != undefined); + assert(resX.msgs[0].whenCreated != undefined); + assert(resX.msgs[0].name == "XZ"); + + var rescount = ldb.search("(|(caseattr=*)(cn=*))", "cn=parttest", ldb.SCOPE_DEFAULT, attrs); + assert(rescount.msgs.length == 5); + + /* Check this attribute is *not* case sensitive */ + var resXcount = ldb.search("caseattr=x*", "cn=parttest", ldb.SCOPE_DEFAULT, attrs); + assert(resXcount.msgs.length == 2); + + /* Check that this attribute *is* case sensitive */ + var resXcount2 = ldb.search("caseattr2=xz", "cn=parttest", ldb.SCOPE_DEFAULT, attrs); + assert(resXcount2.msgs.length == 0); + + + /* Now abort the transaction to show that even with + * partitions, it is aborted everywhere */ + ok = ldb.transaction_cancel(); + if (!ok) { + println("Failed to cancel a transaction: " + ok.errstr); + assert(ok); + } + + /* now check it all went away */ + + var attrs = new Array("highestCommittedUSN"); + var res9 = ldb.search("", "", ldb.SCOPE_BASE, attrs); + assert(usn == res9.msgs[0].highestCommittedUSN); + + var attrs = new Array("*"); + var res10 = ldb.search("x=11", "cn=sub,cn=parttest", ldb.SCOPE_DEFAULT, attrs); + assert(res10.msgs.length == 0); + + var attrs = new Array("*"); + var res11 = ldb.search("x=10", "cn=parttest", ldb.SCOPE_DEFAULT, attrs); + assert(res11.msgs.length == 0); + + var attrs = new Array("*"); + var res12 = ldb.search("caseattr=*", "cn=parttest", ldb.SCOPE_DEFAULT, attrs); + assert(res12.msgs.length == 0); + +} + +sys = sys_init(); +var dbfile = "test.ldb"; + +sys.unlink(prefix + "/" + dbfile); +sys.unlink(prefix + "/" + "testpartition.ldb"); +sys.unlink(prefix + "/" + "testsub.ldb"); +sys.unlink(prefix + "/" + "testsubsub.ldb"); +sys.unlink(prefix + "/" + "testside.ldb"); + +var ok = ldb.connect("tdb://" + prefix + "/" + dbfile); +assert(ok); + +basic_tests(ldb); + +setup_modules(ldb); +ldb = ldb_init(); +var ok = ldb.connect("tdb://" + prefix + "/" + dbfile); +assert(ok); + +parttestldb = ldb_init(); +var ok = parttestldb.connect("tdb://" + prefix + "/" + "testpartition.ldb"); +assert(ok); + +modules_test(ldb, parttestldb); + +sys.unlink(prefix + "/" + dbfile); +sys.unlink(prefix + "/" + "testpartition.ldb"); +sys.unlink(prefix + "/" + "testsub.ldb"); +sys.unlink(prefix + "/" + "testsubsub.ldb"); +sys.unlink(prefix + "/" + "testside.ldb"); +return 0; diff --git a/testprogs/ejs/minschema.js b/testprogs/ejs/minschema.js new file mode 100755 index 0000000000..f088501c1d --- /dev/null +++ b/testprogs/ejs/minschema.js @@ -0,0 +1,804 @@ +#!/bin/sh +exec smbscript "$0" ${1+"$@"} +/* + work out the minimal schema for a set of objectclasses +*/ + +libinclude("base.js"); + +var ldb = ldb_init(); + +var options = GetOptions(ARGV, + "POPT_AUTOHELP", + "POPT_COMMON_SAMBA", + "POPT_COMMON_CREDENTIALS", + "verbose", + "classes", + "attributes"); +if (options == undefined) { + println("Failed to parse options"); + return -1; +} +verbose = options["verbose"]; +dump_all = "yes"; +dump_classes = options["classes"]; +dump_attributes = options["attributes"]; + +if (dump_classes != undefined) { + dump_all = undefined; +} +if (dump_attributes != undefined) { + dump_all = undefined; +} +if (dump_all != undefined) { + dump_classes = "yes"; + dump_attributes = "yes"; +} + +if (options.ARGV.length != 2) { + println("Usage: minschema.js <URL> <classfile>"); + return -1; +} + +var url = options.ARGV[0]; +var classfile = options.ARGV[1]; + +/* use command line creds if available */ +ldb.credentials = options.get_credentials(); + +var ok = ldb.connect(url); +assert(ok); + +objectclasses = new Object(); +attributes = new Object(); +rootDse = new Object(); + +objectclasses_expanded = new Object(); + +/* the attributes we need for objectclasses */ +class_attrs = new Array("objectClass", + "subClassOf", + "governsID", + "possSuperiors", + "possibleInferiors", + "mayContain", + "mustContain", + "auxiliaryClass", + "rDNAttID", + "showInAdvancedViewOnly", + "adminDisplayName", + "adminDescription", + "objectClassCategory", + "lDAPDisplayName", + "schemaIDGUID", + "systemOnly", + "systemPossSuperiors", + "systemMayContain", + "systemMustContain", + "systemAuxiliaryClass", + "defaultSecurityDescriptor", + "systemFlags", + "defaultHidingValue", + "defaultObjectCategory", + + /* this attributes are not used by w2k3 */ + "schemaFlagsEx", + "msDs-IntId", + "msDs-Schema-Extensions", + "classDisplayName", + "isDefunct"); + + +attrib_attrs = new Array("objectClass", + "attributeID", + "attributeSyntax", + "isSingleValued", + "rangeLower", + "rangeUpper", + "mAPIID", + "linkID", + "showInAdvancedViewOnly", + "adminDisplayName", + "oMObjectClass", + "adminDescription", + "oMSyntax", + "searchFlags", + "extendedCharsAllowed", + "lDAPDisplayName", + "schemaIDGUID", + "attributeSecurityGUID", + "systemOnly", + "systemFlags", + "isMemberOfPartialAttributeSet", + + /* this attributes are not used by w2k3 */ + "schemaFlagsEx", + "msDs-IntId", + "msDs-Schema-Extensions", + "classDisplayName", + "isEphemeral", + "isDefunct"); + +/* + notes: + + objectClassCategory + 1: structural + 2: abstract + 3: auxiliary +*/ + + +/* + print only if verbose is set +*/ +function dprintf() { + if (verbose != undefined) { + print(vsprintf(arguments)); + } +} + +function get_object_cn(ldb, name) { + var attrs = new Array("cn"); + + var res = ldb.search(sprintf("(ldapDisplayName=%s)", name), rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, attrs); + assert(res != undefined); + assert(res.msgs.length == 1); + + var cn = res.msgs[0]["cn"]; + assert(cn != undefined); + if (typeof(cn) == "string") { + return cn; + } + return cn[0]; +} +/* + create an objectclass object +*/ +function obj_objectClass(ldb, name) { + var o = new Object(); + o.name = name; + o.cn = get_object_cn(ldb, name); + return o; +} + +/* + create an attribute object +*/ +function obj_attribute(ldb, name) { + var o = new Object(); + o.name = name; + o.cn = get_object_cn(ldb, name); + return o; +} + + +syntaxmap = new Object(); + +syntaxmap['2.5.5.1'] = '1.3.6.1.4.1.1466.115.121.1.12'; +syntaxmap['2.5.5.2'] = '1.3.6.1.4.1.1466.115.121.1.38'; +syntaxmap['2.5.5.3'] = '1.2.840.113556.1.4.1362'; +syntaxmap['2.5.5.4'] = '1.2.840.113556.1.4.905'; +syntaxmap['2.5.5.5'] = '1.3.6.1.4.1.1466.115.121.1.26'; +syntaxmap['2.5.5.6'] = '1.3.6.1.4.1.1466.115.121.1.36'; +syntaxmap['2.5.5.7'] = '1.2.840.113556.1.4.903'; +syntaxmap['2.5.5.8'] = '1.3.6.1.4.1.1466.115.121.1.7'; +syntaxmap['2.5.5.9'] = '1.3.6.1.4.1.1466.115.121.1.27'; +syntaxmap['2.5.5.10'] = '1.3.6.1.4.1.1466.115.121.1.40'; +syntaxmap['2.5.5.11'] = '1.3.6.1.4.1.1466.115.121.1.24'; +syntaxmap['2.5.5.12'] = '1.3.6.1.4.1.1466.115.121.1.15'; +syntaxmap['2.5.5.13'] = '1.3.6.1.4.1.1466.115.121.1.43'; +syntaxmap['2.5.5.14'] = '1.2.840.113556.1.4.904'; +syntaxmap['2.5.5.15'] = '1.2.840.113556.1.4.907'; +syntaxmap['2.5.5.16'] = '1.2.840.113556.1.4.906'; +syntaxmap['2.5.5.17'] = '1.3.6.1.4.1.1466.115.121.1.40'; + +/* + map some attribute syntaxes from some apparently MS specific + syntaxes to the standard syntaxes +*/ +function map_attribute_syntax(s) { + if (syntaxmap[s] != undefined) { + return syntaxmap[s]; + } + return s; +} + + +/* + fix a string DN to use ${SCHEMADN} +*/ +function fix_dn(dn) { + var s = strstr(dn, rootDse.schemaNamingContext); + if (s == NULL) { + return dn; + } + return substr(dn, 0, strlen(dn) - strlen(s)) + "${SCHEMADN}"; +} + +/* + dump an object as ldif +*/ +function write_ldif_one(o, attrs) { + var i; + printf("dn: CN=%s,${SCHEMADN}\n", o.cn); + for (i=0;i<attrs.length;i++) { + var a = attrs[i]; + if (o[a] == undefined) { + continue; + } + /* special case for oMObjectClass, which is a binary object */ + if (a == "oMObjectClass") { + printf("%s:: %s\n", a, o[a]); + continue; + } + var v = o[a]; + if (typeof(v) == "string") { + v = new Array(v); + } + var j; + for (j=0;j<v.length;j++) { + printf("%s: %s\n", a, fix_dn(v[j])); + } + } + printf("\n"); +} + +/* + dump an array of objects as ldif +*/ +function write_ldif(o, attrs) { + var i; + for (i in o) { + write_ldif_one(o[i], attrs); + } +} + + +/* + create a testDN based an an example DN + the idea is to ensure we obey any structural rules +*/ +function create_testdn(exampleDN) { + var a = split(",", exampleDN); + a[0] = "CN=TestDN"; + return join(",", a); +} + +/* + find the properties of an objectclass + */ +function find_objectclass_properties(ldb, o) { + var res = ldb.search( + sprintf("(ldapDisplayName=%s)", o.name), + rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, class_attrs); + assert(res != undefined); + assert(res.msgs.length == 1); + var msg = res.msgs[0]; + var a; + for (a in msg) { + o[a] = msg[a]; + } +} + +/* + find the properties of an attribute + */ +function find_attribute_properties(ldb, o) { + var res = ldb.search( + sprintf("(ldapDisplayName=%s)", o.name), + rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, attrib_attrs); + assert(res != undefined); + assert(res.msgs.length == 1); + var msg = res.msgs[0]; + var a; + for (a in msg) { + /* special case for oMObjectClass, which is a binary object */ + if (a == "oMObjectClass") { + o[a] = ldb.encode(msg[a]); + continue; + } + o[a] = msg[a]; + } +} + +/* + find the auto-created properties of an objectclass. Only works for classes + that can be created using just a DN and the objectclass + */ +function find_objectclass_auto(ldb, o) { + if (o["exampleDN"] == undefined) { + return; + } + var testdn = create_testdn(o.exampleDN); + var ok; + + dprintf("testdn is '%s'\n", testdn); + + var ldif = "dn: " + testdn; + ldif = ldif + "\nobjectClass: " + o.name; + ok = ldb.add(ldif); + if (ok.error != 0) { + dprintf("error adding %s: %s\n", o.name, ok.errstr); + dprintf("%s\n", ldif); + return; + } + + var res = ldb.search("", testdn, ldb.SCOPE_BASE); + ok = ldb.del(testdn); + assert(ok.error == 0); + + var a; + for (a in res.msgs[0]) { + attributes[a].autocreate = true; + } +} + + +/* + look at auxiliary information from a class to intuit the existance of more + classes needed for a minimal schema +*/ +function expand_objectclass(ldb, o) { + var attrs = new Array("auxiliaryClass", "systemAuxiliaryClass", + "possSuperiors", "systemPossSuperiors", + "subClassOf"); + var res = ldb.search( + sprintf("(&(objectClass=classSchema)(ldapDisplayName=%s))", o.name), + rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, attrs); + var a; + dprintf("Expanding class %s\n", o.name); + assert(res != undefined); + assert(res.msgs.length == 1); + var msg = res.msgs[0]; + for (a=0;a<attrs.length;a++) { + var aname = attrs[a]; + if (msg[aname] == undefined) { + continue; + } + var list = msg[aname]; + if (typeof(list) == "string") { + list = new Array(msg[aname]); + } + var i; + for (i=0;i<list.length;i++) { + var name = list[i]; + if (objectclasses[name] == undefined) { + dprintf("Found new objectclass '%s'\n", name); + objectclasses[name] = obj_objectClass(ldb, name); + } + } + } +} + + +/* + add the must and may attributes from an objectclass to the full list + of attributes +*/ +function add_objectclass_attributes(ldb, class) { + var attrs = new Array("mustContain", "systemMustContain", + "mayContain", "systemMayContain"); + var i; + for (i=0;i<attrs.length;i++) { + var aname = attrs[i]; + if (class[aname] == undefined) { + continue; + } + var alist = class[aname]; + if (typeof(alist) == "string") { + alist = new Array(alist); + } + var j; + var len = alist.length; + for (j=0;j<len;j++) { + var a = alist[j]; + if (attributes[a] == undefined) { + attributes[a] = obj_attribute(ldb, a); + } + } + } +} + + +/* + process an individual record, working out what attributes it has +*/ +function walk_dn(ldb, dn) { + /* get a list of all possible attributes for this object */ + var attrs = new Array("allowedAttributes"); + var res = ldb.search("objectClass=*", dn, ldb.SCOPE_BASE, attrs); + if (res.error != 0) { + dprintf("Unable to fetch allowedAttributes for '%s' - %s\n", + dn, res.errstr); + return; + } + var allattrs = res.msgs[0].allowedAttributes; + res = ldb.search("objectClass=*", dn, ldb.SCOPE_BASE, allattrs); + if (res.error != 0) { + dprintf("Unable to fetch all attributes for '%s' - %s\n", + dn, res.errstr); + return; + } + var a; + var msg = res.msgs[0]; + for (a in msg) { + if (attributes[a] == undefined) { + attributes[a] = obj_attribute(ldb, a); + } + } +} + +/* + walk a naming context, looking for all records +*/ +function walk_naming_context(ldb, namingContext) { + var attrs = new Array("objectClass"); + var res = ldb.search("objectClass=*", namingContext, ldb.SCOPE_DEFAULT, attrs); + if (res.error != 0) { + dprintf("Unable to fetch objectClasses for '%s' - %s\n", + namingContext, res.errstr); + return; + } + var r; + for (r=0;r<res.msgs.length;r++) { + var msg = res.msgs[r].objectClass; + var c; + for (c=0;c<msg.length;c++) { + var objectClass = msg[c]; + if (objectclasses[objectClass] == undefined) { + objectclasses[objectClass] = obj_objectClass(ldb, objectClass); + objectclasses[objectClass].exampleDN = res.msgs[r].dn; + } + } + walk_dn(ldb, res.msgs[r].dn); + } +} + +/* + trim the may attributes for an objectClass +*/ +function trim_objectclass_attributes(ldb, class) { + var i,j,n; + + /* trim possibleInferiors, + * include only the classes we extracted */ + var possinf = class["possibleInferiors"]; + if (possinf != undefined) { + var newpossinf = new Array(); + if (typeof(possinf) == "string") { + possinf = new Array(possinf); + } + n = 0; + for (j = 0;j < possinf.length; j++) { + var x = possinf[j]; + if (objectclasses[x] != undefined) { + newpossinf[n] = x; + n++; + } + } + class["possibleInferiors"] = newpossinf; + } + + /* trim systemMayContain, + * remove duplicates */ + var sysmay = class["systemMayContain"]; + if (sysmay != undefined) { + var newsysmay = new Array(); + if (typeof(sysmay) == "string") { + sysmay = new Array(sysmay); + } + for (j = 0;j < sysmay.length; j++) { + var x = sysmay[j]; + var dup = false; + if (newsysmay[0] == undefined) { + newsysmay[0] = x; + } else { + for (n = 0; n < newsysmay.length; n++) { + if (newsysmay[n] == x) { + dup = true; + } + } + if (dup == false) { + newsysmay[n] = x; + } + } + } + class["systemMayContain"] = newsysmay; + } + + /* trim mayContain, + * remove duplicates */ + var may = class["mayContain"]; + if (may != undefined) { + var newmay = new Array(); + if (typeof(may) == "string") { + may = new Array(may); + } + for (j = 0;j < may.length; j++) { + var x = may[j]; + var dup = false; + if (newmay[0] == undefined) { + newmay[0] = x; + } else { + for (n = 0; n < newmay.length; n++) { + if (newmay[n] == x) { + dup = true; + } + } + if (dup == false) { + newmay[n] = x; + } + } + } + class["mayContain"] = newmay; + } +} + +/* + load the basic attributes of an objectClass +*/ +function build_objectclass(ldb, name) { + var attrs = new Array("name"); + var res = ldb.search( + sprintf("(&(objectClass=classSchema)(ldapDisplayName=%s))", name), + rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, attrs); + if (res.error != 0) { + dprintf("unknown class '%s'\n", name); + return undefined; + } + if (res.msgs.length == 0) { + dprintf("unknown class '%s'\n", name); + return undefined; + } + return obj_objectClass(ldb, name); +} + +/* + append 2 lists +*/ +function list_append(a1, a2) { + var i; + if (a1 == undefined) { + return a2; + } + if (a2 == undefined) { + return a1; + } + for (i=0;i<a2.length;i++) { + a1[a1.length] = a2[i]; + } + return a1; +} + +/* + form a coalesced attribute list +*/ +function attribute_list(class, attr1, attr2) { + var a1 = class[attr1]; + var a2 = class[attr2]; + if (typeof(a1) == "string") { + a1 = new Array(a1); + } + if (typeof(a2) == "string") { + a2 = new Array(a2); + } + return list_append(a1, a2); +} + +/* + write out a list in aggregate form +*/ +function aggregate_list(name, list) { + if (list == undefined) { + return; + } + var i; + printf("%s ( ", name); + for (i=0;i<list.length;i++) { + printf("%s ", list[i]); + if (i < (list.length - 1)) { + printf("$ "); + } + } + printf(") "); +} + +/* + write the aggregate record for an objectclass +*/ +function write_aggregate_objectclass(class) { + printf("objectClasses: ( %s NAME '%s' ", class.governsID, class.name); + if (class['subClassOf'] != undefined) { + printf("SUP %s ", class['subClassOf']); + } + if (class.objectClassCategory == 1) { + printf("STRUCTURAL "); + } else if (class.objectClassCategory == 2) { + printf("ABSTRACT "); + } else if (class.objectClassCategory == 3) { + printf("AUXILIARY "); + } + + var list; + + list = attribute_list(class, "systemMustContain", "mustContain"); + aggregate_list("MUST", list); + + list = attribute_list(class, "systemMayContain", "mayContain"); + aggregate_list("MAY", list); + + printf(")\n"); +} + + +/* + write the aggregate record for an ditcontentrule +*/ +function write_aggregate_ditcontentrule(class) { + var list = attribute_list(class, "auxiliaryClass", "systemAuxiliaryClass"); + var i; + if (list == undefined) { + return; + } + + printf("dITContentRules: ( %s NAME '%s' ", class.governsID, class.name); + + aggregate_list("AUX", list); + + var may_list = undefined; + var must_list = undefined; + + for (i=0;i<list.length;i++) { + var c = list[i]; + var list2; + list2 = attribute_list(objectclasses[c], + "mayContain", "systemMayContain"); + may_list = list_append(may_list, list2); + list2 = attribute_list(objectclasses[c], + "mustContain", "systemMustContain"); + must_list = list_append(must_list, list2); + } + + aggregate_list("MUST", must_list); + aggregate_list("MAY", may_list); + + printf(")\n"); +} + +/* + write the aggregate record for an attribute +*/ +function write_aggregate_attribute(attrib) { + printf("attributeTypes: ( %s NAME '%s' SYNTAX '%s' ", + attrib.attributeID, attrib.name, + map_attribute_syntax(attrib.attributeSyntax)); + if (attrib['isSingleValued'] == "TRUE") { + printf("SINGLE-VALUE "); + } + if (attrib['systemOnly'] == "TRUE") { + printf("NO-USER-MODIFICATION "); + } + + printf(")\n"); +} + + + +/* + load a list from a file +*/ +function load_list(file) { + var sys = sys_init(); + var s = sys.file_load(file); + var a = split("\n", s); + return a; +} + +/* get the rootDSE */ +var res = ldb.search("", "", ldb.SCOPE_BASE); +rootDse = res.msgs[0]; + +/* load the list of classes we are interested in */ +var classes = load_list(classfile); +var i; +for (i=0;i<classes.length;i++) { + var classname = classes[i]; + var class = build_objectclass(ldb, classname); + if (class != undefined) { + objectclasses[classname] = class; + } +} + + +/* + expand the objectclass list as needed +*/ +var num_classes = 0; +var expanded = 0; +/* calculate the actual number of classes */ +for (i in objectclasses) { + num_classes++; +} +/* so EJS do not have while nor the break statement + cannot find any other way than doing more loops + than necessary to recursively expand all classes + */ +var inf; +for (inf = 0;inf < 500; inf++) { + if (expanded < num_classes) { + for (i in objectclasses) { + var n = objectclasses[i]; + if (objectclasses_expanded[i] != "DONE") { + expand_objectclass(ldb, objectclasses[i]); + objectclasses_expanded[i] = "DONE"; + expanded++; + } + } + /* recalculate the actual number of classes */ + num_classes = 0; + for (i in objectclasses) { + num_classes++; + } + } +} + +/* + find objectclass properties +*/ +for (i in objectclasses) { + find_objectclass_properties(ldb, objectclasses[i]); +} + +/* + form the full list of attributes +*/ +for (i in objectclasses) { + add_objectclass_attributes(ldb, objectclasses[i]); +} + +/* and attribute properties */ +for (i in attributes) { + find_attribute_properties(ldb, attributes[i]); +} + +/* + trim the 'may' attribute lists to those really needed +*/ +for (i in objectclasses) { + trim_objectclass_attributes(ldb, objectclasses[i]); +} + +/* + dump an ldif form of the attributes and objectclasses +*/ +if (dump_attributes != undefined) { + write_ldif(attributes, attrib_attrs); +} +if (dump_classes != undefined) { + write_ldif(objectclasses, class_attrs); +} +if (verbose == undefined) { + exit(0); +} + +/* + dump list of objectclasses +*/ +printf("objectClasses:\n") +for (i in objectclasses) { + printf("\t%s\n", i); +} +printf("attributes:\n") +for (i in attributes) { + printf("\t%s\n", i); +} + +printf("autocreated attributes:\n"); +for (i in attributes) { + if (attributes[i].autocreate == true) { + printf("\t%s\n", i); + } +} + +return 0; diff --git a/testprogs/ejs/minschema_classes.txt b/testprogs/ejs/minschema_classes.txt new file mode 100644 index 0000000000..30f5b8ce96 --- /dev/null +++ b/testprogs/ejs/minschema_classes.txt @@ -0,0 +1,41 @@ +applicationSettings +builtinDomain +classSchema +computer +configuration +container +crossRef +crossRefContainer +dMD +domain +domainDNS +foreignSecurityPrincipal +group +infrastructureUpdate +leaf +nTDSDSA +nTDSService +organizationalPerson +organizationalUnit +person +primaryDomain +rIDManager +secret +server +serversContainer +site +sitesContainer +subSchema +user +displaySpecifier +foreignSecurityPrincipal +trustedDomain +attributeSchema +subSchema +queryPolicy +groupPolicyContainer +ipsecPolicy +ipsecISAKMPPolicy +ipsecNFA +ipsecFilter +ipsecNegotiationPolicy diff --git a/testprogs/ejs/samba3sam.js b/testprogs/ejs/samba3sam.js new file mode 100644 index 0000000000..e5639b8ec8 --- /dev/null +++ b/testprogs/ejs/samba3sam.js @@ -0,0 +1,1255 @@ +#!/usr/bin/env smbscript +/* + (C) Jelmer Vernooij <jelmer@samba.org> 2005 + (C) Martin Kuehl <mkhl@samba.org> 2006 + Published under the GNU GPL + Sponsored by Google Summer of Code + */ + +var sys; +var options = GetOptions(ARGV, "POPT_AUTOHELP", "POPT_COMMON_SAMBA"); +if (options == undefined) { + println("Failed to parse options"); + return -1; +} + +libinclude("base.js"); + +if (options.ARGV.length != 2) { + println("Usage: samba3sam.js <TESTDIR> <DATADIR>"); + return -1; +} + +var prefix = options.ARGV[0]; +var datadir = options.ARGV[1]; + +function setup_data(obj, ldif) +{ + assert(ldif != undefined); + ldif = substitute_var(ldif, obj); + assert(ldif != undefined); + var ok = obj.db.add(ldif); + assert(ok.error == 0); +} + +function setup_modules(ldb, s3, s4, ldif) +{ + assert(ldif != undefined); + ldif = substitute_var(ldif, s4); + assert(ldif != undefined); + var ok = ldb.add(ldif); + assert(ok.error == 0); + + var ldif = " +dn: @MAP=samba3sam +@FROM: " + s4.BASEDN + " +@TO: sambaDomainName=TESTS," + s3.BASEDN + " + +dn: @MODULES +@LIST: rootdse,paged_results,server_sort,extended_dn,asq,samldb,password_hash,operational,objectguid,rdn_name,samba3sam,partition + +dn: @PARTITION +partition: " + s4.BASEDN + ":" + s4.url + " +partition: " + s3.BASEDN + ":" + s3.url + " +replicateEntries: @SUBCLASSES +replicateEntries: @ATTRIBUTES +replicateEntries: @INDEXLIST +"; + var ok = ldb.add(ldif); + assert(ok.error == 0); +} + +function test_s3sam_search(ldb) +{ + println("Looking up by non-mapped attribute"); + var msg = ldb.search("(cn=Administrator)"); + assert(msg.error == 0); + assert(msg.msgs.length == 1); + assert(msg.msgs[0].cn == "Administrator"); + + println("Looking up by mapped attribute"); + var msg = ldb.search("(name=Backup Operators)"); + assert(msg.error == 0); + assert(msg.msgs.length == 1); + assert(msg.msgs[0].name == "Backup Operators"); + + println("Looking up by old name of renamed attribute"); + var msg = ldb.search("(displayName=Backup Operators)"); + assert(msg.msgs.length == 0); + + println("Looking up mapped entry containing SID"); + var msg = ldb.search("(cn=Replicator)"); + assert(msg.error == 0); + assert(msg.msgs.length == 1); + println(msg.msgs[0].dn); + assert(msg.msgs[0].dn == "cn=Replicator,ou=Groups,dc=vernstok,dc=nl"); + assert(msg.msgs[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552"); + + println("Checking mapping of objectClass"); + var oc = msg.msgs[0].objectClass; + assert(oc != undefined); + for (var i in oc) { + assert(oc[i] == "posixGroup" || oc[i] == "group"); + } + + println("Looking up by objectClass"); + var msg = ldb.search("(|(objectClass=user)(cn=Administrator))"); + assert(msg.error == 0); + assert(msg.msgs.length == 2); + for (var i = 0; i < msg.msgs.length; i++) { + assert((msg.msgs[i].dn == "unixName=Administrator,ou=Users,dc=vernstok,dc=nl") || + (msg.msgs[i].dn == "unixName=nobody,ou=Users,dc=vernstok,dc=nl")); + } +} + +function test_s3sam_modify(ldb, s3) +{ + var msg, ok; + println("Adding a record that will be fallbacked"); + ok = ldb.add(" +dn: cn=Foo +foo: bar +blah: Blie +cn: Foo +showInAdvancedViewOnly: TRUE +"); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + + println("Checking for existence of record (local)"); + /* TODO: This record must be searched in the local database, which is currently only supported for base searches + * msg = ldb.search("(cn=Foo)", new Array('foo','blah','cn','showInAdvancedViewOnly')); + * TODO: Actually, this version should work as well but doesn't... + * + */ + var attrs = new Array('foo','blah','cn','showInAdvancedViewOnly'); + msg = ldb.search("(cn=Foo)", "cn=Foo", ldb.LDB_SCOPE_BASE, attrs); + assert(msg.error == 0); + assert(msg.msgs.length == 1); + assert(msg.msgs[0].showInAdvancedViewOnly == "TRUE"); + assert(msg.msgs[0].foo == "bar"); + assert(msg.msgs[0].blah == "Blie"); + + println("Adding record that will be mapped"); + ok = ldb.add(" +dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl +objectClass: user +unixName: bin +sambaUnicodePwd: geheim +cn: Niemand +"); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + assert(ok.error == 0); + + println("Checking for existence of record (remote)"); + msg = ldb.search("(unixName=bin)", new Array('unixName','cn','dn', 'sambaUnicodePwd')); + assert(msg.error == 0); + assert(msg.msgs.length == 1); + assert(msg.msgs[0].cn == "Niemand"); + assert(msg.msgs[0].sambaUnicodePwd == "geheim"); + + println("Checking for existence of record (local && remote)"); + msg = ldb.search("(&(unixName=bin)(sambaUnicodePwd=geheim))", new Array('unixName','cn','dn', 'sambaUnicodePwd')); + assert(msg.error == 0); + assert(msg.msgs.length == 1); // TODO: should check with more records + assert(msg.msgs[0].cn == "Niemand"); + assert(msg.msgs[0].unixName == "bin"); + assert(msg.msgs[0].sambaUnicodePwd == "geheim"); + + println("Checking for existence of record (local || remote)"); + msg = ldb.search("(|(unixName=bin)(sambaUnicodePwd=geheim))", new Array('unixName','cn','dn', 'sambaUnicodePwd')); + println("got " + msg.msgs.length + " replies"); + assert(msg.error == 0); + assert(msg.msgs.length == 1); // TODO: should check with more records + assert(msg.msgs[0].cn == "Niemand"); + assert(msg.msgs[0].unixName == "bin" || msg.msgs[0].sambaUnicodePwd == "geheim"); + + println("Checking for data in destination database"); + msg = s3.db.search("(cn=Niemand)"); + assert(msg.error == 0); + assert(msg.msgs.length >= 1); + assert(msg.msgs[0].sambaSID == "S-1-5-21-4231626423-2410014848-2360679739-2001"); + assert(msg.msgs[0].displayName == "Niemand"); + + println("Adding attribute..."); + ok = ldb.modify(" +dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl +changetype: modify +add: description +description: Blah +"); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + assert(ok.error == 0); + + println("Checking whether changes are still there..."); + msg = ldb.search("(cn=Niemand)"); + assert(msg.error == 0); + assert(msg.msgs.length >= 1); + assert(msg.msgs[0].cn == "Niemand"); + assert(msg.msgs[0].description == "Blah"); + + println("Modifying attribute..."); + ok = ldb.modify(" +dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl +changetype: modify +replace: description +description: Blie +"); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + assert(ok.error == 0); + + println("Checking whether changes are still there..."); + msg = ldb.search("(cn=Niemand)"); + assert(msg.error == 0); + assert(msg.msgs.length >= 1); + assert(msg.msgs[0].description == "Blie"); + + println("Deleting attribute..."); + ok = ldb.modify(" +dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl +changetype: modify +delete: description +"); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + assert(ok.error == 0); + + println("Checking whether changes are no longer there..."); + msg = ldb.search("(cn=Niemand)"); + assert(msg.error == 0); + assert(msg.msgs.length >= 1); + assert(msg.msgs[0].description == undefined); + + println("Renaming record..."); + ok = ldb.rename("cn=Niemand,cn=Users,dc=vernstok,dc=nl", "cn=Niemand2,cn=Users,dc=vernstok,dc=nl"); + assert(ok.error == 0); + + println("Checking whether DN has changed..."); + msg = ldb.search("(cn=Niemand2)"); + assert(msg.error == 0); + assert(msg.msgs.length == 1); + assert(msg.msgs[0].dn == "cn=Niemand2,cn=Users,dc=vernstok,dc=nl"); + + println("Deleting record..."); + ok = ldb.del("cn=Niemand2,cn=Users,dc=vernstok,dc=nl"); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + + println("Checking whether record is gone..."); + msg = ldb.search("(cn=Niemand2)"); + assert(msg.error == 0); + assert(msg.msgs.length == 0); +} + +function test_map_search(ldb, s3, s4) +{ + println("Running search tests on mapped data"); + var res; + var dn; + var attrs; + + + var ldif = " +dn: " + "sambaDomainName=TESTS," + s3.BASEDN + " +objectclass: sambaDomain +objectclass: top +sambaSID: S-1-5-21-4231626423-2410014848-2360679739 +sambaNextRid: 2000 +sambaDomainName: TESTS" + ldif = substitute_var(ldif, s3); + assert(ldif != undefined); + var ok = s3.db.add(ldif); + assert(ok.error == 0); + + printf("Add a set of split records"); + var ldif = " +dn: " + s4.dn("cn=X") + " +objectClass: user +cn: X +codePage: x +revision: x +dnsHostName: x +nextRid: y +lastLogon: x +description: x +objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 +primaryGroupID: 1-5-21-4231626423-2410014848-2360679739-512 + +dn: " + s4.dn("cn=Y") + " +objectClass: top +cn: Y +codePage: x +revision: x +dnsHostName: y +nextRid: y +lastLogon: y +description: x + +dn: " + s4.dn("cn=Z") + " +objectClass: top +cn: Z +codePage: x +revision: y +dnsHostName: z +nextRid: y +lastLogon: z +description: y +"; + + ldif = substitute_var(ldif, s4); + assert(ldif != undefined); + var ok = ldb.add(ldif); + if (ok.error != 0) { + println(ok.errstr); + assert(ok.error == 0); + } + + println("Add a set of remote records"); + + var ldif = " +dn: " + s3.dn("cn=A") + " +objectClass: posixAccount +cn: A +sambaNextRid: x +sambaBadPasswordCount: x +sambaLogonTime: x +description: x +sambaSID: S-1-5-21-4231626423-2410014848-2360679739-552 +sambaPrimaryGroupSID: S-1-5-21-4231626423-2410014848-2360679739-512 + +dn: " + s3.dn("cn=B") + " +objectClass: top +cn:B +sambaNextRid: x +sambaBadPasswordCount: x +sambaLogonTime: y +description: x + +dn: " + s3.dn("cn=C") + " +objectClass: top +cn: C +sambaNextRid: x +sambaBadPasswordCount: y +sambaLogonTime: z +description: y +"; + ldif = substitute_var(ldif, s3); + assert(ldif != undefined); + var ok = s3.db.add(ldif); + assert(ok.error == 0); + + println("Testing search by DN"); + + /* Search remote record by local DN */ + dn = s4.dn("cn=A"); + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "x"); + + /* Search remote record by remote DN */ + dn = s3.dn("cn=A"); + attrs = new Array("dnsHostName", "lastLogon", "sambaLogonTime"); + res = s3.db.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == undefined); + assert(res.msgs[0].sambaLogonTime == "x"); + + /* Search split record by local DN */ + dn = s4.dn("cn=X"); + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].dnsHostName == "x"); + assert(res.msgs[0].lastLogon == "x"); + + /* Search split record by remote DN */ + dn = s3.dn("cn=X"); + attrs = new Array("dnsHostName", "lastLogon", "sambaLogonTime"); + res = s3.db.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == undefined); + assert(res.msgs[0].sambaLogonTime == "x"); + + println("Testing search by attribute"); + + /* Search by ignored attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(revision=x)", NULL, ldb. SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 2); + assert(res.msgs[0].dn == s4.dn("cn=Y")); + assert(res.msgs[0].dnsHostName == "y"); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=X")); + assert(res.msgs[1].dnsHostName == "x"); + assert(res.msgs[1].lastLogon == "x"); + + /* Search by kept attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(description=y)", NULL, ldb. SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 2); + assert(res.msgs[0].dn == s4.dn("cn=Z")); + assert(res.msgs[0].dnsHostName == "z"); + assert(res.msgs[0].lastLogon == "z"); + assert(res.msgs[1].dn == s4.dn("cn=C")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "z"); + + /* Search by renamed attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(badPwdCount=x)", NULL, ldb. SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 2); + assert(res.msgs[0].dn == s4.dn("cn=B")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=A")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "x"); + + /* Search by converted attribute */ + attrs = new Array("dnsHostName", "lastLogon", "objectSid"); + /* TODO: + Using the SID directly in the parse tree leads to conversion + errors, letting the search fail with no results. + res = ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-552)", NULL, ldb. SCOPE_DEFAULT, attrs); + */ + res = ldb.search("(objectSid=*)", NULL, ldb. SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 3); + assert(res.msgs[0].dn == s4.dn("cn=X")); + assert(res.msgs[0].dnsHostName == "x"); + assert(res.msgs[0].lastLogon == "x"); + assert(res.msgs[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552"); + assert(res.msgs[1].dn == s4.dn("cn=A")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[1].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552"); + + /* Search by generated attribute */ + /* In most cases, this even works when the mapping is missing + * a `convert_operator' by enumerating the remote db. */ + attrs = new Array("dnsHostName", "lastLogon", "primaryGroupID"); + res = ldb.search("(primaryGroupID=512)", NULL, ldb. SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == s4.dn("cn=A")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "x"); + assert(res.msgs[0].primaryGroupID == "512"); + + /* TODO: There should actually be two results, A and X. The + * primaryGroupID of X seems to get corrupted somewhere, and the + * objectSid isn't available during the generation of remote (!) data, + * which can be observed with the following search. Also note that Xs + * objectSid seems to be fine in the previous search for objectSid... */ + /* + res = ldb.search("(primaryGroupID=*)", NULL, ldb. SCOPE_DEFAULT, attrs); + println(res.msgs.length + " results found"); + for (i=0;i<res.msgs.length;i++) { + for (obj in res.msgs[i]) { + println(obj + ": " + res.msgs[i][obj]); + } + println("---"); + } + */ + + /* Search by remote name of renamed attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(sambaBadPasswordCount=*)", "", ldb. SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 0); + + /* Search by objectClass */ + attrs = new Array("dnsHostName", "lastLogon", "objectClass"); + res = ldb.search("(objectClass=user)", NULL, ldb. SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 2); + assert(res.msgs[0].dn == s4.dn("cn=X")); + assert(res.msgs[0].dnsHostName == "x"); + assert(res.msgs[0].lastLogon == "x"); + assert(res.msgs[0].objectClass != undefined); + assert(res.msgs[0].objectClass[0] == "user"); + assert(res.msgs[1].dn == s4.dn("cn=A")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[1].objectClass != undefined); + assert(res.msgs[1].objectClass[0] == "user"); + + /* Prove that the objectClass is actually used for the search */ + res = ldb.search("(|(objectClass=user)(badPwdCount=x))", NULL, ldb. SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 3); + assert(res.msgs[0].dn == s4.dn("cn=B")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[0].objectClass != undefined); + for (i=0;i<res.msgs[0].objectClass.length;i++) { + assert(res.msgs[0].objectClass[i] != "user"); + } + assert(res.msgs[1].dn == s4.dn("cn=X")); + assert(res.msgs[1].dnsHostName == "x"); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[1].objectClass != undefined); + assert(res.msgs[1].objectClass[0] == "user"); + assert(res.msgs[2].dn == s4.dn("cn=A")); + assert(res.msgs[2].dnsHostName == undefined); + assert(res.msgs[2].lastLogon == "x"); + assert(res.msgs[2].objectClass != undefined); + assert(res.msgs[2].objectClass[0] == "user"); + + println("Testing search by parse tree"); + + /* Search by conjunction of local attributes */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(&(codePage=x)(revision=x))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 2); + assert(res.msgs[0].dn == s4.dn("cn=Y")); + assert(res.msgs[0].dnsHostName == "y"); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=X")); + assert(res.msgs[1].dnsHostName == "x"); + assert(res.msgs[1].lastLogon == "x"); + + /* Search by conjunction of remote attributes */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(&(lastLogon=x)(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 2); + assert(res.msgs[0].dn == s4.dn("cn=X")); + assert(res.msgs[0].dnsHostName == "x"); + assert(res.msgs[0].lastLogon == "x"); + assert(res.msgs[1].dn == s4.dn("cn=A")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "x"); + + /* Search by conjunction of local and remote attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(&(codePage=x)(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 2); + assert(res.msgs[0].dn == s4.dn("cn=Y")); + assert(res.msgs[0].dnsHostName == "y"); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=X")); + assert(res.msgs[1].dnsHostName == "x"); + assert(res.msgs[1].lastLogon == "x"); + + /* Search by conjunction of local and remote attribute w/o match */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(&(codePage=x)(nextRid=x))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 0); + res = ldb.search("(&(revision=x)(lastLogon=z))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 0); + + /* Search by disjunction of local attributes */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(|(revision=x)(dnsHostName=x))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 2); + assert(res.msgs[0].dn == s4.dn("cn=Y")); + assert(res.msgs[0].dnsHostName == "y"); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=X")); + assert(res.msgs[1].dnsHostName == "x"); + assert(res.msgs[1].lastLogon == "x"); + + /* Search by disjunction of remote attributes */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(|(badPwdCount=x)(lastLogon=x))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 3); + assert(res.msgs[0].dn == s4.dn("cn=B")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=X")); + assert(res.msgs[1].dnsHostName == "x"); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[2].dn == s4.dn("cn=A")); + assert(res.msgs[2].dnsHostName == undefined); + assert(res.msgs[2].lastLogon == "x"); + + /* Search by disjunction of local and remote attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(|(revision=x)(lastLogon=y))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 3); + assert(res.msgs[0].dn == s4.dn("cn=Y")); + assert(res.msgs[0].dnsHostName == "y"); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=B")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "y"); + assert(res.msgs[2].dn == s4.dn("cn=X")); + assert(res.msgs[2].dnsHostName == "x"); + assert(res.msgs[2].lastLogon == "x"); + + /* Search by disjunction of local and remote attribute w/o match */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(|(codePage=y)(nextRid=z))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 0); + + /* Search by negated local attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(!(revision=x))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 5); + assert(res.msgs[0].dn == s4.dn("cn=B")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=A")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[2].dn == s4.dn("cn=Z")); + assert(res.msgs[2].dnsHostName == "z"); + assert(res.msgs[2].lastLogon == "z"); + assert(res.msgs[3].dn == s4.dn("cn=C")); + assert(res.msgs[3].dnsHostName == undefined); + assert(res.msgs[3].lastLogon == "z"); + + /* Search by negated remote attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(!(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 3); + assert(res.msgs[0].dn == s4.dn("cn=Z")); + assert(res.msgs[0].dnsHostName == "z"); + assert(res.msgs[0].lastLogon == "z"); + assert(res.msgs[1].dn == s4.dn("cn=C")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "z"); + + /* Search by negated conjunction of local attributes */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(!(&(codePage=x)(revision=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 5); + assert(res.msgs[0].dn == s4.dn("cn=B")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=A")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[2].dn == s4.dn("cn=Z")); + assert(res.msgs[2].dnsHostName == "z"); + assert(res.msgs[2].lastLogon == "z"); + assert(res.msgs[3].dn == s4.dn("cn=C")); + assert(res.msgs[3].dnsHostName == undefined); + assert(res.msgs[3].lastLogon == "z"); + + /* Search by negated conjunction of remote attributes */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(!(&(lastLogon=x)(description=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 5); + assert(res.msgs[0].dn == s4.dn("cn=Y")); + assert(res.msgs[0].dnsHostName == "y"); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=B")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "y"); + assert(res.msgs[2].dn == s4.dn("cn=Z")); + assert(res.msgs[2].dnsHostName == "z"); + assert(res.msgs[2].lastLogon == "z"); + assert(res.msgs[3].dn == s4.dn("cn=C")); + assert(res.msgs[3].dnsHostName == undefined); + assert(res.msgs[3].lastLogon == "z"); + + /* Search by negated conjunction of local and remote attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(!(&(codePage=x)(description=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 5); + assert(res.msgs[0].dn == s4.dn("cn=B")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=A")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[2].dn == s4.dn("cn=Z")); + assert(res.msgs[2].dnsHostName == "z"); + assert(res.msgs[2].lastLogon == "z"); + assert(res.msgs[3].dn == s4.dn("cn=C")); + assert(res.msgs[3].dnsHostName == undefined); + assert(res.msgs[3].lastLogon == "z"); + + /* Search by negated disjunction of local attributes */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(!(|(revision=x)(dnsHostName=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs[0].dn == s4.dn("cn=B")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=A")); + assert(res.msgs[1].dnsHostName == undefined); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[2].dn == s4.dn("cn=Z")); + assert(res.msgs[2].dnsHostName == "z"); + assert(res.msgs[2].lastLogon == "z"); + assert(res.msgs[3].dn == s4.dn("cn=C")); + assert(res.msgs[3].dnsHostName == undefined); + assert(res.msgs[3].lastLogon == "z"); + + /* Search by negated disjunction of remote attributes */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(!(|(badPwdCount=x)(lastLogon=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 4); + assert(res.msgs[0].dn == s4.dn("cn=Y")); + assert(res.msgs[0].dnsHostName == "y"); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=Z")); + assert(res.msgs[1].dnsHostName == "z"); + assert(res.msgs[1].lastLogon == "z"); + assert(res.msgs[2].dn == s4.dn("cn=C")); + assert(res.msgs[2].dnsHostName == undefined); + assert(res.msgs[2].lastLogon == "z"); + + /* Search by negated disjunction of local and remote attribute */ + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(!(|(revision=x)(lastLogon=y)))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 4); + assert(res.msgs[0].dn == s4.dn("cn=A")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "x"); + assert(res.msgs[1].dn == s4.dn("cn=Z")); + assert(res.msgs[1].dnsHostName == "z"); + assert(res.msgs[1].lastLogon == "z"); + assert(res.msgs[2].dn == s4.dn("cn=C")); + assert(res.msgs[2].dnsHostName == undefined); + assert(res.msgs[2].lastLogon == "z"); + + println("Search by complex parse tree"); + attrs = new Array("dnsHostName", "lastLogon"); + res = ldb.search("(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 6); + assert(res.msgs[0].dn == s4.dn("cn=B")); + assert(res.msgs[0].dnsHostName == undefined); + assert(res.msgs[0].lastLogon == "y"); + assert(res.msgs[1].dn == s4.dn("cn=X")); + assert(res.msgs[1].dnsHostName == "x"); + assert(res.msgs[1].lastLogon == "x"); + assert(res.msgs[2].dn == s4.dn("cn=A")); + assert(res.msgs[2].dnsHostName == undefined); + assert(res.msgs[2].lastLogon == "x"); + assert(res.msgs[3].dn == s4.dn("cn=Z")); + assert(res.msgs[3].dnsHostName == "z"); + assert(res.msgs[3].lastLogon == "z"); + assert(res.msgs[4].dn == s4.dn("cn=C")); + assert(res.msgs[4].dnsHostName == undefined); + assert(res.msgs[4].lastLogon == "z"); + + /* Clean up */ + var dns = new Array(); + dns[0] = s4.dn("cn=A"); + dns[1] = s4.dn("cn=B"); + dns[2] = s4.dn("cn=C"); + dns[3] = s4.dn("cn=X"); + dns[4] = s4.dn("cn=Y"); + dns[5] = s4.dn("cn=Z"); + for (i=0;i<dns.length;i++) { + var ok = ldb.del(dns[i]); + assert(ok.error == 0); + } +} + +function test_map_modify(ldb, s3, s4) +{ + println("Running modification tests on mapped data"); + + var ldif; + var attrs; + var dn, dn2; + var res; + var ok; + + println("Testing modification of local records"); + + /* Add local record */ + dn = "cn=test,dc=idealx,dc=org"; + ldif = " +dn: " + dn + " +cn: test +foo: bar +revision: 1 +description: test +"; + ok = ldb.add(ldif); + assert(ok.error == 0); + /* Check it's there */ + attrs = new Array("foo", "revision", "description"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].foo == "bar"); + assert(res.msgs[0].revision == "1"); + assert(res.msgs[0].description == "test"); + /* Check it's not in the local db */ + res = s4.db.search("(cn=test)", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 0); + /* Check it's not in the remote db */ + res = s3.db.search("(cn=test)", NULL, ldb.SCOPE_DEFAULT, attrs); + assert(res.error == 0); + assert(res.msgs.length == 0); + + /* Modify local record */ + ldif = " +dn: " + dn + " +replace: foo +foo: baz +replace: description +description: foo +"; + ok = ldb.modify(ldif); + assert(ok.error == 0); + /* Check in local db */ + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].foo == "baz"); + assert(res.msgs[0].revision == "1"); + assert(res.msgs[0].description == "foo"); + + /* Rename local record */ + dn2 = "cn=toast,dc=idealx,dc=org"; + ok = ldb.rename(dn, dn2); + assert(ok.error == 0); + /* Check in local db */ + res = ldb.search("", dn2, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn2); + assert(res.msgs[0].foo == "baz"); + assert(res.msgs[0].revision == "1"); + assert(res.msgs[0].description == "foo"); + + /* Delete local record */ + ok = ldb.del(dn2); + assert(ok.error == 0); + /* Check it's gone */ + res = ldb.search("", dn2, ldb.SCOPE_BASE); + assert(res.error == 0); + assert(res.msgs.length == 0); + + println("Testing modification of remote records"); + + /* Add remote record */ + dn = s4.dn("cn=test"); + dn2 = s3.dn("cn=test"); + ldif = " +dn: " + dn2 + " +cn: test +description: foo +sambaBadPasswordCount: 3 +sambaNextRid: 1001 +"; + ok = s3.db.add(ldif); + assert(ok.error == 0); + /* Check it's there */ + attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid"); + res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn2); + assert(res.msgs[0].description == "foo"); + assert(res.msgs[0].sambaBadPasswordCount == "3"); + assert(res.msgs[0].sambaNextRid == "1001"); + /* Check in mapped db */ + attrs = new Array("description", "badPwdCount", "nextRid"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == "foo"); + assert(res.msgs[0].badPwdCount == "3"); + assert(res.msgs[0].nextRid == "1001"); + /* Check in local db */ + res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 0); + + /* Modify remote data of remote record */ + ldif = " +dn: " + dn + " +replace: description +description: test +replace: badPwdCount +badPwdCount: 4 +"; + ok = ldb.modify(ldif); + /* Check in mapped db */ + attrs = new Array("description", "badPwdCount", "nextRid"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].badPwdCount == "4"); + assert(res.msgs[0].nextRid == "1001"); + /* Check in remote db */ + attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid"); + res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn2); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].sambaBadPasswordCount == "4"); + assert(res.msgs[0].sambaNextRid == "1001"); + + /* Rename remote record */ + dn2 = s4.dn("cn=toast"); + ok = ldb.rename(dn, dn2); + assert(ok.error == 0); + /* Check in mapped db */ + dn = dn2; + attrs = new Array("description", "badPwdCount", "nextRid"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].badPwdCount == "4"); + assert(res.msgs[0].nextRid == "1001"); + /* Check in remote db */ + dn2 = s3.dn("cn=toast"); + attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid"); + res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn2); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].sambaBadPasswordCount == "4"); + assert(res.msgs[0].sambaNextRid == "1001"); + + /* Delete remote record */ + ok = ldb.del(dn); + assert(ok.error == 0); + /* Check in mapped db */ + res = ldb.search("", dn, ldb.SCOPE_BASE); + assert(res.error == 0); + assert(res.msgs.length == 0); + /* Check in remote db */ + res = s3.db.search("", dn2, ldb.SCOPE_BASE); + assert(res.error == 0); + assert(res.msgs.length == 0); + + /* Add remote record (same as before) */ + dn = s4.dn("cn=test"); + dn2 = s3.dn("cn=test"); + ldif = " +dn: " + dn2 + " +cn: test +description: foo +sambaBadPasswordCount: 3 +sambaNextRid: 1001 +"; + ok = s3.db.add(ldif); + assert(ok.error == 0); + + /* Modify local data of remote record */ + ldif = " +dn: " + dn + " +add: revision +revision: 1 +replace: description +description: test +"; + ok = ldb.modify(ldif); + /* Check in mapped db */ + attrs = new Array("revision", "description"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].revision == "1"); + /* Check in remote db */ + res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn2); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].revision == undefined); + /* Check in local db */ + res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == undefined); + assert(res.msgs[0].revision == "1"); + + /* Delete (newly) split record */ + ok = ldb.del(dn); + assert(ok.error == 0); + + println("Testing modification of split records"); + + /* Add split record */ + dn = s4.dn("cn=test"); + dn2 = s3.dn("cn=test"); + ldif = " +dn: " + dn + " +cn: test +description: foo +badPwdCount: 3 +nextRid: 1001 +revision: 1 +"; + ok = ldb.add(ldif); + assert(ok.error == 0); + /* Check it's there */ + attrs = new Array("description", "badPwdCount", "nextRid", "revision"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == "foo"); + assert(res.msgs[0].badPwdCount == "3"); + assert(res.msgs[0].nextRid == "1001"); + assert(res.msgs[0].revision == "1"); + /* Check in local db */ + res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == undefined); + assert(res.msgs[0].badPwdCount == undefined); + assert(res.msgs[0].nextRid == undefined); + assert(res.msgs[0].revision == "1"); + /* Check in remote db */ + attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision"); + res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn2); + assert(res.msgs[0].description == "foo"); + assert(res.msgs[0].sambaBadPasswordCount == "3"); + assert(res.msgs[0].sambaNextRid == "1001"); + assert(res.msgs[0].revision == undefined); + + /* Modify of split record */ + ldif = " +dn: " + dn + " +replace: description +description: test +replace: badPwdCount +badPwdCount: 4 +replace: revision +revision: 2 +"; + ok = ldb.modify(ldif); + assert(ok.error == 0); + /* Check in mapped db */ + attrs = new Array("description", "badPwdCount", "nextRid", "revision"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].badPwdCount == "4"); + assert(res.msgs[0].nextRid == "1001"); + assert(res.msgs[0].revision == "2"); + /* Check in local db */ + res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == undefined); + assert(res.msgs[0].badPwdCount == undefined); + assert(res.msgs[0].nextRid == undefined); + assert(res.msgs[0].revision == "2"); + /* Check in remote db */ + attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision"); + res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn2); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].sambaBadPasswordCount == "4"); + assert(res.msgs[0].sambaNextRid == "1001"); + assert(res.msgs[0].revision == undefined); + + /* Rename split record */ + dn2 = s4.dn("cn=toast"); + ok = ldb.rename(dn, dn2); + assert(ok.error == 0); + /* Check in mapped db */ + dn = dn2; + attrs = new Array("description", "badPwdCount", "nextRid", "revision"); + res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].badPwdCount == "4"); + assert(res.msgs[0].nextRid == "1001"); + assert(res.msgs[0].revision == "2"); + /* Check in local db */ + res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn); + assert(res.msgs[0].description == undefined); + assert(res.msgs[0].badPwdCount == undefined); + assert(res.msgs[0].nextRid == undefined); + assert(res.msgs[0].revision == "2"); + /* Check in remote db */ + dn2 = s3.dn("cn=toast"); + attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision"); + res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); + assert(res.error == 0); + assert(res.msgs.length == 1); + assert(res.msgs[0].dn == dn2); + assert(res.msgs[0].description == "test"); + assert(res.msgs[0].sambaBadPasswordCount == "4"); + assert(res.msgs[0].sambaNextRid == "1001"); + assert(res.msgs[0].revision == undefined); + + /* Delete split record */ + ok = ldb.del(dn); + assert(ok.error == 0); + /* Check in mapped db */ + res = ldb.search("", dn, ldb.SCOPE_BASE); + assert(res.error == 0); + assert(res.msgs.length == 0); + /* Check in local db */ + res = s4.db.search("", dn, ldb.SCOPE_BASE); + assert(res.error == 0); + assert(res.msgs.length == 0); + /* Check in remote db */ + res = s3.db.search("", dn2, ldb.SCOPE_BASE); + assert(res.error == 0); + assert(res.msgs.length == 0); +} + +function make_dn(rdn) +{ + return rdn + ",sambaDomainName=TESTS," + this.BASEDN; +} + +function make_s4dn(rdn) +{ + return rdn + "," + this.BASEDN; +} + +var ldb = ldb_init(); + +sys = sys_init(); +var ldbfile = prefix + "/" + "test.ldb"; +var ldburl = "tdb://" + ldbfile; + +var samba4 = new Object("samba4 partition info"); +samba4.file = prefix + "/" + "samba4.ldb"; +samba4.url = "tdb://" + samba4.file; +samba4.BASEDN = "dc=vernstok,dc=nl"; +samba4.db = ldb_init(); +samba4.dn = make_s4dn; + +var samba3 = new Object("samba3 partition info"); +samba3.file = prefix + "/" + "samba3.ldb"; +samba3.url = "tdb://" + samba3.file; +samba3.BASEDN = "cn=Samba3Sam"; +samba3.db = ldb_init(); +samba3.dn = make_dn; + +var templates = new Object("templates partition info"); +templates.file = prefix + "/" + "templates.ldb"; +templates.url = "tdb://" + templates.file; +templates.BASEDN = "cn=templates"; +templates.db = ldb_init(); + +sys.unlink(ldbfile); +sys.unlink(samba3.file); +sys.unlink(templates.file); +sys.unlink(samba4.file); + +var ok = ldb.connect(ldburl); +assert(ok); +var ok = samba3.db.connect(samba3.url); +assert(ok); +var ok = templates.db.connect(templates.url); +assert(ok); +var ok = samba4.db.connect(samba4.url); +assert(ok); + +setup_data(samba3, sys.file_load(datadir + "/" + "samba3.ldif")); +setup_data(templates, sys.file_load(datadir + "/" + "provision_samba3sam_templates.ldif")); +setup_modules(ldb, samba3, samba4, sys.file_load(datadir + "/" + "provision_samba3sam.ldif")); + +ldb = ldb_init(); +var ok = ldb.connect(ldburl); +assert(ok); + +test_s3sam_search(ldb); +test_s3sam_modify(ldb, samba3); + +sys.unlink(ldbfile); +sys.unlink(samba3.file); +sys.unlink(templates.file); +sys.unlink(samba4.file); + +ldb = ldb_init(); +var ok = ldb.connect(ldburl); +assert(ok); +samba3.db = ldb_init(); +var ok = samba3.db.connect(samba3.url); +assert(ok); +templates.db = ldb_init(); +var ok = templates.db.connect(templates.url); +assert(ok); +samba4.db = ldb_init(); +var ok = samba4.db.connect(samba4.url); +assert(ok); + +setup_data(templates, sys.file_load(datadir + "/" + "provision_samba3sam_templates.ldif")); +setup_modules(ldb, samba3, samba4, sys.file_load(datadir + "provision_samba3sam.ldif")); + +ldb = ldb_init(); +var ok = ldb.connect(ldburl); +assert(ok); + +test_map_search(ldb, samba3, samba4); +test_map_modify(ldb, samba3, samba4); + +sys.unlink(ldbfile); +sys.unlink(samba3.file); +sys.unlink(samba4.file); + +return 0; diff --git a/testprogs/ejs/sprintf.js b/testprogs/ejs/sprintf.js new file mode 100755 index 0000000000..6ae8605718 --- /dev/null +++ b/testprogs/ejs/sprintf.js @@ -0,0 +1,31 @@ +#!/usr/bin/env smbscript +/* + test sprintf function +*/ + +string_init(local); + +function check_result(s, v) +{ + if (s != v) { + println("expected '" + v + "' but got '" + s + "'"); + } + assert(s == v); +} + +function xprintf() +{ + return "XX{" + vsprintf(arguments) + "}XX"; +} + +check_result(sprintf("%d", 7), "7"); +check_result(sprintf("%04d", 42), "0042"); +check_result(sprintf("my string=%7.2s", "foo%7"), "my string= fo"); +check_result(sprintf("blah=0x%*x", 4, 19), "blah=0x 13"); +check_result(sprintf("blah=0x%0*x", 4, 19), "blah=0x0013"); +check_result(sprintf("blah=%.0f", 1032), "blah=1032"); +check_result(sprintf("%4.2f%%", 72.32), "72.32%"); + +check_result(xprintf("%4.2f%% and %s", 72.32, "foo"),"XX{72.32% and foo}XX"); + +println("ALL OK"); diff --git a/testprogs/win32/midltests/midltests.acf b/testprogs/win32/midltests/midltests.acf new file mode 100644 index 0000000000..a04bb5dcd9 --- /dev/null +++ b/testprogs/win32/midltests/midltests.acf @@ -0,0 +1,6 @@ +[ + implicit_handle (handle_t midltests_IfHandle) +] +interface midltests +{ +} diff --git a/testprogs/win32/midltests/midltests.c b/testprogs/win32/midltests/midltests.c new file mode 100644 index 0000000000..61d4ce0812 --- /dev/null +++ b/testprogs/win32/midltests/midltests.c @@ -0,0 +1,42 @@ +/* + MIDLTESTS client. + + Copyright (C) Stefan Metzmacher 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "midltests.h" + +#define MIDLTESTS_C_CODE 1 +#include "midltests.idl" + +int main(int argc, char **argv) +{ + int ret; + + midltests_IfHandle = NULL; + + RpcTryExcept { + midltests(); + } RpcExcept(1) { + ret = RpcExceptionCode(); + printf("Runtime error 0x%x\n", ret); + } RpcEndExcept + + return ret; +} diff --git a/testprogs/win32/midltests/midltests.idl b/testprogs/win32/midltests/midltests.idl new file mode 100644 index 0000000000..1932549c56 --- /dev/null +++ b/testprogs/win32/midltests/midltests.idl @@ -0,0 +1,27 @@ +#ifndef MIDLTESTS_C_CODE + +[ + uuid("225b9fcb-eb3d-497b-8b0b-591f049a2507"), + pointer_default(unique) +] +interface midltests +{ + long midltests_fn( + ); +} + +#elif MIDLTESTS_C_CODE + +static void midltests(void) +{ + cli_midltests_fn(); +} + +long srv_midltests_fn(void) +{ + printf("srv_midltests_fn: Start\n"); + printf("srv_midltests_fn: End\n"); + return 0x65757254; +} + +#endif
\ No newline at end of file diff --git a/testprogs/win32/midltests/midltests_c_m.c b/testprogs/win32/midltests/midltests_c_m.c new file mode 100644 index 0000000000..facf735304 --- /dev/null +++ b/testprogs/win32/midltests/midltests_c_m.c @@ -0,0 +1,2 @@ +#include "midltests_marshall.h" +#include "midltests_c.c" diff --git a/testprogs/win32/midltests/midltests_marshall.c b/testprogs/win32/midltests/midltests_marshall.c new file mode 100644 index 0000000000..e772afd03d --- /dev/null +++ b/testprogs/win32/midltests/midltests_marshall.c @@ -0,0 +1,121 @@ +/* + MIDLTESTS client. + + Copyright (C) Stefan Metzmacher 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "midltests.h" + +#define MIN(a,b) ((a)<(b)?(a):(b)) +static void print_asc(const unsigned char *buf,int len) +{ + int i; + for (i=0;i<len;i++) + printf("%c", isprint(buf[i])?buf[i]:'.'); +} + +static void dump_data(const unsigned char *buf1,int len) +{ + const unsigned char *buf = (const unsigned char *)buf1; + int i=0; + if (len<=0) return; + + printf("[%03X] ",i); + for (i=0;i<len;) { + printf("%02X ",(int)buf[i]); + i++; + if (i%8 == 0) printf(" "); + if (i%16 == 0) { + print_asc(&buf[i-16],8); printf(" "); + print_asc(&buf[i-8],8); printf("\n"); + if (i<len) printf("[%03X] ",i); + } + } + if (i%16) { + int n; + n = 16 - (i%16); + printf(" "); + if (n>8) printf(" "); + while (n--) printf(" "); + n = MIN(8,i%16); + print_asc(&buf[i-(i%16)],n); printf( " " ); + n = (i%16) - n; + if (n>0) print_asc(&buf[i-n],n); + printf("\n"); + } +} + +void NdrGetBufferMarshall(PMIDL_STUB_MESSAGE stubmsg, unsigned long len, RPC_BINDING_HANDLE hnd) +{ + stubmsg->RpcMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, len); + memset(stubmsg->RpcMsg->Buffer, 0xef, len); + stubmsg->RpcMsg->BufferLength = len; + stubmsg->Buffer = stubmsg->RpcMsg->Buffer; + stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; + stubmsg->fBufferValid = TRUE; +} + +void __RPC_STUB midltests_midltests_fn(PRPC_MESSAGE _pRpcMessage); + +void NdrSendReceiveMarshall(PMIDL_STUB_MESSAGE StubMsg, unsigned char *buffer) +{ + unsigned long DataRepresentation; + + StubMsg->RpcMsg->BufferLength = buffer - (unsigned char *)StubMsg->RpcMsg->Buffer; + + printf("[in] Buffer[%d/%d]\n", + StubMsg->RpcMsg->BufferLength, StubMsg->BufferLength); + dump_data(StubMsg->RpcMsg->Buffer, StubMsg->RpcMsg->BufferLength); + + DataRepresentation = StubMsg->RpcMsg->DataRepresentation; + StubMsg->RpcMsg->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; + midltests_midltests_fn(StubMsg->RpcMsg); + StubMsg->RpcMsg->DataRepresentation = DataRepresentation; + + StubMsg->BufferLength = StubMsg->RpcMsg->BufferLength; + StubMsg->BufferStart = StubMsg->RpcMsg->Buffer; + StubMsg->BufferEnd = StubMsg->BufferStart + StubMsg->BufferLength; + StubMsg->Buffer = StubMsg->BufferStart; + + printf("[out] Buffer[%d]\n", + StubMsg->RpcMsg->BufferLength); + dump_data(StubMsg->RpcMsg->Buffer, StubMsg->RpcMsg->BufferLength); +} + +void NdrServerInitializeNewMarshall(PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc) +{ + memset(pStubMsg, 0, sizeof(*pStubMsg)); + pStubMsg->RpcMsg = pRpcMsg; + pStubMsg->Buffer = pStubMsg->BufferStart = pRpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->Buffer + pRpcMsg->BufferLength; + pStubMsg->BufferLength = pRpcMsg->BufferLength; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->dwDestContext = MSHCTX_DIFFERENTMACHINE; +} + +RPC_STATUS WINAPI I_RpcGetBufferMarshall(PRPC_MESSAGE RpcMsg) +{ + RpcMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, RpcMsg->BufferLength); + memset(RpcMsg->Buffer, 0xcd, RpcMsg->BufferLength); + return 0; +} diff --git a/testprogs/win32/midltests/midltests_marshall.h b/testprogs/win32/midltests/midltests_marshall.h new file mode 100644 index 0000000000..0c6aed2721 --- /dev/null +++ b/testprogs/win32/midltests/midltests_marshall.h @@ -0,0 +1,16 @@ +#include "rpc.h" +#include "rpcndr.h" +#define NdrSendReceive NdrSendReceiveMarshall +void NdrSendReceiveMarshall(PMIDL_STUB_MESSAGE stubmsg, unsigned char *buffer); +#define NdrGetBuffer NdrGetBufferMarshall +void NdrGetBufferMarshall(PMIDL_STUB_MESSAGE stubmsg, unsigned long len, RPC_BINDING_HANDLE hnd); +#define NdrServerInitializeNew NdrServerInitializeNewMarshall +void NdrServerInitializeNewMarshall(PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc); +#define I_RpcGetBuffer I_RpcGetBufferMarshall +RPC_STATUS WINAPI I_RpcGetBufferMarshall(PRPC_MESSAGE pMsg); + + + + diff --git a/testprogs/win32/midltests/midltests_s_m.c b/testprogs/win32/midltests/midltests_s_m.c new file mode 100644 index 0000000000..7e0862dc69 --- /dev/null +++ b/testprogs/win32/midltests/midltests_s_m.c @@ -0,0 +1,2 @@ +#include "midltests_marshall.h" +#include "midltests_s.c" diff --git a/testprogs/win32/midltests/utils.c b/testprogs/win32/midltests/utils.c new file mode 100644 index 0000000000..8c4833ddb4 --- /dev/null +++ b/testprogs/win32/midltests/utils.c @@ -0,0 +1,32 @@ +/* + MIDLTESTS utility functions. + + Copyright (C) Tim Potter 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "midltests.h" + +/* MIDL allocate and free functions */ + +void __RPC_FAR *__RPC_USER midl_user_allocate(size_t len) +{ + return(malloc(len)); +} + +void __RPC_USER midl_user_free(void __RPC_FAR *ptr) +{ + free(ptr); +} diff --git a/testprogs/win32/npecho/GNUmakefile b/testprogs/win32/npecho/GNUmakefile new file mode 100755 index 0000000000..33cf95def1 --- /dev/null +++ b/testprogs/win32/npecho/GNUmakefile @@ -0,0 +1,20 @@ +INCLUDES=-I. +CFLAGS=$(INCLUDES) + +all: npecho_client.exe npecho_server.exe + +CC = i586-mingw32msvc-gcc + +.SUFFIXES: .c .obj + +.c.obj: + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + del *~ *.obj *.exe + +npecho_client.exe: npecho_client.obj +npecho_server.exe: npecho_server.obj + +%.exe: + $(CC) $(CFLAGS) -o $@ $< $(LIBS) diff --git a/testprogs/win32/npecho/NMakefile b/testprogs/win32/npecho/NMakefile new file mode 100755 index 0000000000..b52a9c7ab7 --- /dev/null +++ b/testprogs/win32/npecho/NMakefile @@ -0,0 +1,13 @@ +INCLUDES=-I +CFLAGS=$(INCLUDES) -Zi -nologo + +all: npecho_client.exe npecho_server.exe + +clean: + del *~ *.obj *.exe + +npecho_client.exe: npecho_client.obj + $(CC) $(CFLAGS) -o npecho_client.exe npecho_client.obj $(LIBS) + +npecho_server.exe: npecho_server.obj + $(CC) $(CFLAGS) -o npecho_server.exe npecho_server.obj $(LIBS) diff --git a/testprogs/win32/npecho/npecho_client.c b/testprogs/win32/npecho/npecho_client.c new file mode 100755 index 0000000000..97d31c4318 --- /dev/null +++ b/testprogs/win32/npecho/npecho_client.c @@ -0,0 +1,50 @@ +/* + * Simple Named Pipe Client + * (C) 2005 Jelmer Vernooij <jelmer@samba.org> + * Published to the public domain + */ + +#include <windows.h> +#include <stdio.h> + +#define ECHODATA "Black Dog" + +int main(int argc, char *argv[]) +{ + HANDLE h; + DWORD numread = 0; + char *outbuffer = malloc(strlen(ECHODATA)); + + if (argc == 1) { + printf("Usage: %s pipename\n", argv[0]); + printf(" Where pipename is something like \\\\servername\\NPECHO\n"); + return -1; + } + + h = CreateFile(argv[1], GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (h == INVALID_HANDLE_VALUE) { + printf("Error opening: %d\n", GetLastError()); + return -1; + } + + if (!WriteFile(h, ECHODATA, strlen(ECHODATA), &numread, NULL)) { + printf("Error writing: %d\n", GetLastError()); + return -1; + } + + if (!ReadFile(h, outbuffer, strlen(ECHODATA), &numread, NULL)) { + printf("Error reading: %d\n", GetLastError()); + return -1; + } + + printf("Read: %s\n", outbuffer); + + if (!TransactNamedPipe(h, ECHODATA, strlen(ECHODATA), outbuffer, strlen(ECHODATA), &numread, NULL)) { + printf("TransactNamedPipe failed: %d!\n", GetLastError()); + return -1; + } + + printf("Result: %s\n", outbuffer); + + return 0; +} diff --git a/testprogs/win32/rpcecho/Makefile b/testprogs/win32/rpcecho/Makefile new file mode 100644 index 0000000000..ca0c823eab --- /dev/null +++ b/testprogs/win32/rpcecho/Makefile @@ -0,0 +1,23 @@ +INCLUDES=-I +CFLAGS=$(INCLUDES) -Zi -nologo +LIBS=rpcrt4.lib + +all: client server + +clean: + del *~ *.obj client server rpcecho_c.c rpcecho_s.c rpcecho.h + +rpcecho.h rpcecho_s.c rpcecho_c.c: rpcecho.idl rpcecho.acf + midl rpcecho.idl + +client: client.obj rpcecho_c.obj utils.obj + $(CC) $(CFLAGS) -o client client.obj rpcecho_c.obj utils.obj $(LIBS) + +server: server.obj rpcecho_s.obj utils.obj + $(CC) $(CFLAGS) -o server server.obj rpcecho_s.obj utils.obj $(LIBS) + +client.obj: rpcecho.h client.c +server.obj: rpcecho.h server.c +rpcecho_c.obj: rpcecho.h rpcecho_c.c +rpcecho_s.obj: rpcecho.h rpcecho_s.c +utils.obj: rpcecho.h utils.c diff --git a/testprogs/win32/rpcecho/README b/testprogs/win32/rpcecho/README new file mode 100644 index 0000000000..2eb6ab9847 --- /dev/null +++ b/testprogs/win32/rpcecho/README @@ -0,0 +1,46 @@ +This directory contains two win32 programs to test large RPC requests +and responses. The two programs are: + + server A command line RPC server that listens and processes + RPC requests on the \pipe\rpcecho named pipe. + + client A command line RPC client program that + +Samba also implements the client and server sides of the rpcecho pipe +if the --enable-developer option to configure has been used. The +rpcclient(1) program is used to implement the client side RPC +operations. + +There are currently four RPC calls defined in the rpcecho pipe. They +are: + + AddOne Adds one to an integer sent by the client + + EchoData The client sends an array of bytes and it is echoed + back by the server. + + SourceData The client sends an array of bytes and it is discarded + by the server. + + SinkData The server returns an array of bytes. + +The Ethereal network protocol decoder (http://www.ethereal.com/) also +contains support for the rpcecho pipe as part of its DCERPC for +Windows. + +Starting the win32 server program is easy. Just run server.exe in a +command window. The win32 client program is also run from a command +window. The usage information is shown below: + + Usage: client hostname cmd [args] + + Where hostname is the name of the host to connect to, + and cmd is the command to execute with optional args: + + addone num Add one to num and return the result + echodata size Send an array of size bytes and receive it back + sinkdata size Send an array of size bytes + sourcedata size Receive an array of size bytes + +Tim Potter +tpot@samba.org diff --git a/testprogs/win32/rpcecho/client.c b/testprogs/win32/rpcecho/client.c new file mode 100644 index 0000000000..dae2a4bec3 --- /dev/null +++ b/testprogs/win32/rpcecho/client.c @@ -0,0 +1,367 @@ +/* + RPC echo client. + + Copyright (C) Tim Potter 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "rpcecho.h" + +void main(int argc, char **argv) +{ + RPC_STATUS status; + char *binding = NULL; + const char *username=NULL; + const char *password=NULL; + const char *domain=NULL; + unsigned sec_options = 0; + + argv += 1; + argc -= 1; + + while (argc > 2 && argv[0][0] == '-') { + const char *option; + + switch (argv[0][1]) { + case 'e': + binding = argv[1]; + break; + case 'u': + username = argv[1]; + break; + case 'p': + password = argv[1]; + break; + case 'd': + domain = argv[1]; + break; + case '-': + option = &argv[0][2]; + if (strcmp(option, "sign") == 0) { + if (sec_options == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) { + printf("You must choose sign or seal, not both\n"); + exit(1); + } + sec_options = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY; + } else if (strcmp(option, "seal") == 0) { + if (sec_options == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) { + printf("You must choose sign or seal, not both\n"); + exit(1); + } + sec_options = RPC_C_AUTHN_LEVEL_PKT_PRIVACY; + } else { + printf("Bad security option '%s'\n", option); + exit(1); + } + argv++; + argc--; + continue; + default: + printf("Bad option -%c\n", argv[0][0]); + exit(1); + } + argv += 2; + argc -= 2; + } + + if (argc < 2) { + printf("Usage: client [options] hostname cmd [args]\n\n"); + printf("Where hostname is the name of the host to connect to,\n"); + printf("and cmd is the command to execute with optional args:\n\n"); + printf("\taddone num\tAdd one to num and return the result\n"); + printf("\techodata size\tSend an array of size bytes and receive it back\n"); + printf("\tsinkdata size\tSend an array of size bytes\n"); + printf("\tsourcedata size\tReceive an array of size bytes\n"); + printf("\ttest\trun testcall\n"); + printf("\noptions:\n"); + printf("\t-u username -d domain -p password -e endpoint\n"); + printf("\t--sign --seal\n"); + printf("\nExamples:\n"); + printf("\tclient HOSTNAME addone 3\n"); + printf("\tclient 192.168.115.1 addone 3\n"); + printf("\tclient -e ncacn_np:HOSTNAME[\\\\pipe\\\\rpcecho] addone 3\n"); + printf("\tclient -e ncacn_ip_tcp:192.168.115.1 addone 3\n"); + printf("\tclient -e ncacn_ip_tcp:192.168.115.1 -u tridge -d MYDOMAIN -p PASSWORD addone 3\n"); + exit(0); + } + + + if (!binding) { + char *network_address = argv[0]; + + argc--; + argv++; + + status = RpcStringBindingCompose( + NULL, /* uuid */ + "ncacn_np", + network_address, + "\\pipe\\rpcecho", + NULL, /* options */ + &binding); + + if (status) { + printf("RpcStringBindingCompose returned %d\n", status); + exit(status); + } + } + + printf("Endpoint is %s\n", binding); + + status = RpcBindingFromStringBinding( + binding, + &rpcecho_IfHandle); + + if (status) { + printf("RpcBindingFromStringBinding returned %d\n", status); + exit(status); + } + + if (username) { + SEC_WINNT_AUTH_IDENTITY ident = { username, strlen(username), + domain, strlen(domain), + password, strlen(password), + SEC_WINNT_AUTH_IDENTITY_ANSI }; + + status = RpcBindingSetAuthInfo(rpcecho_IfHandle, NULL, + sec_options, + RPC_C_AUTHN_WINNT, + &ident, 0); + if (status) { + printf ("RpcBindingSetAuthInfo failed: 0x%x\n", status); + exit (1); + } + } + + + while (argc > 0) { + RpcTryExcept { + + /* Add one to a number */ + + if (strcmp(argv[0], "addone") == 0) { + int arg, result; + + if (argc < 2) { + printf("Usage: addone num\n"); + exit(1); + } + + arg = atoi(argv[1]); + + AddOne(arg, &result); + printf("%d + 1 = %d\n", arg, result); + + argc -= 2; + argv += 2; + continue; + } + + /* Echo an array */ + + if (strcmp(argv[0], "echodata") == 0) { + int arg, i; + char *indata, *outdata; + + if (argc < 2) { + printf("Usage: echo num\n"); + exit(1); + } + + arg = atoi(argv[1]); + + if ((indata = malloc(arg)) == NULL) { + printf("Error allocating %d bytes for input\n", arg); + exit(1); + } + + if ((outdata = malloc(arg)) == NULL) { + printf("Error allocating %d bytes for output\n", arg); + exit(1); + } + + for (i = 0; i < arg; i++) + indata[i] = i & 0xff; + + EchoData(arg, indata, outdata); + + printf("echo %d\n", arg); + + for (i = 0; i < arg; i++) { + if (indata[i] != outdata[i]) { + printf("data mismatch at offset %d, %d != %d\n", + i, indata[i], outdata[i]); + exit(0); + } + } + + argc -= 2; + argv += 2; + continue; + } + + if (strcmp(argv[0], "sinkdata") == 0) { + int arg, i; + char *indata; + + if (argc < 2) { + printf("Usage: sinkdata num\n"); + exit(1); + } + + arg = atoi(argv[1]); + + if ((indata = malloc(arg)) == NULL) { + printf("Error allocating %d bytes for input\n", arg); + exit(1); + } + + for (i = 0; i < arg; i++) + indata[i] = i & 0xff; + + SinkData(arg, indata); + + printf("sinkdata %d\n", arg); + argc -= 2; + argv += 2; + continue; + } + + if (strcmp(argv[0], "sourcedata") == 0) { + int arg, i; + unsigned char *outdata; + + if (argc < 2) { + printf("Usage: sourcedata num\n"); + exit(1); + } + + arg = atoi(argv[1]); + + if ((outdata = malloc(arg)) == NULL) { + printf("Error allocating %d bytes for output\n", arg); + exit(1); + } + + SourceData(arg, outdata); + + printf("sourcedata %d\n", arg); + + for (i = 0; i < arg; i++) { + if (outdata[i] != (i & 0xff)) { + printf("data mismatch at offset %d, %d != %d\n", + i, outdata[i], i & 0xff); + } + } + + argc -= 2; + argv += 2; + continue; + } + + if (strcmp(argv[0], "test") == 0) { + printf("no TestCall\n"); + + argc -= 1; + argv += 1; + continue; + } + + + if (strcmp(argv[0], "enum") == 0) { + enum echo_Enum1 v = ECHO_ENUM1; + echo_Enum2 e2; + echo_Enum3 e3; + + e2.e1 = 76; + e2.e2 = ECHO_ENUM1_32; + e3.e1 = ECHO_ENUM2; + + argc -= 1; + argv += 1; + + echo_TestEnum(&v, &e2, &e3); + + continue; + } + + if (strcmp(argv[0], "double") == 0) { + typedef unsigned short uint16; + uint16 v = 13; + uint16 *pv = &v; + uint16 **ppv = &pv; + uint16 ret; + + argc -= 1; + argv += 1; + + ret = echo_TestDoublePointer(&ppv); + + printf("TestDoublePointer v=%d ret=%d\n", v, ret); + + continue; + } + + if (strcmp(argv[0], "sleep") == 0) { + long arg, result; + + if (argc < 2) { + printf("Usage: sleep num\n"); + exit(1); + } + + arg = atoi(argv[1]); + +// result = TestSleep(arg); +// printf("Slept for %d seconds\n", result); + printf("Sleep disabled (need async code)\n"); + + argc -= 2; + argv += 2; + continue; + } + + printf("Invalid command '%s'\n", argv[0]); + goto done; + + } RpcExcept(1) { + unsigned long ex; + + ex = RpcExceptionCode(); + printf("Runtime error 0x%x\n", ex); + } RpcEndExcept + } + +done: + + status = RpcStringFree(&binding); + + if (status) { + printf("RpcStringFree returned %d\n", status); + exit(status); + } + + status = RpcBindingFree(&rpcecho_IfHandle); + + if (status) { + printf("RpcBindingFree returned %d\n", status); + exit(status); + } + + exit(0); +} diff --git a/testprogs/win32/rpcecho/rpcecho.acf b/testprogs/win32/rpcecho/rpcecho.acf new file mode 100644 index 0000000000..56c7d334f8 --- /dev/null +++ b/testprogs/win32/rpcecho/rpcecho.acf @@ -0,0 +1,26 @@ +/* + RPC echo ACF. + + Copyright (C) Tim Potter 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +[ + implicit_handle (handle_t rpcecho_IfHandle) +] +interface rpcecho +{ +/* [async] TestSleep(); */ +} diff --git a/testprogs/win32/rpcecho/rpcecho.idl b/testprogs/win32/rpcecho/rpcecho.idl new file mode 100644 index 0000000000..b0ddb81a38 --- /dev/null +++ b/testprogs/win32/rpcecho/rpcecho.idl @@ -0,0 +1,146 @@ +/* + RPC echo IDL. + + Copyright (C) Tim Potter 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __PIDL__ +#define unistr [string] wchar_t * +#endif + +[ +uuid(60a15ec5-4de8-11d7-a637-005056a20182), +version(1.0) +] +interface rpcecho +{ + // Add one to an integer + void AddOne( + [in] int in_data, + [out] int *out_data + ); + // Echo an array of bytes back at the caller + void EchoData( + [in] int len, + [in] [size_is(len)] char in_data[], + [out] [size_is(len)] char out_data[] + ); + // Sink data to the server + void SinkData( + [in] int len, + [in] [size_is(len)] char in_data[] + ); + // Source data from server + void SourceData( + [in] int len, + [out] [size_is(len)] char out_data[] + ); + const long myconstant = 42; + + /* test strings */ + void TestCall ( + [in] unistr *s1, + [out] unistr *s2 + ); + + /* test some alignment issues */ + typedef struct { + char v; + } echo_info1; + + typedef struct { + short v; + } echo_info2; + + typedef struct { + long v; + } echo_info3; + + typedef struct { + hyper v; + } echo_info4; + + typedef struct { + char v1; + hyper v2; + } echo_info5; + + typedef struct { + char v1; + echo_info1 info1; + } echo_info6; + + typedef struct { + char v1; + echo_info4 info4; + } echo_info7; + + typedef union { + [case(1)] echo_info1 info1; + [case(2)] echo_info2 info2; + [case(3)] echo_info3 info3; + [case(4)] echo_info4 info4; + [case(5)] echo_info5 info5; + [case(6)] echo_info6 info6; + [case(7)] echo_info7 info7; + } echo_Info; + + long TestCall2 ( + [in] short level, + [out,switch_is(level)] echo_Info **info + ); + + long TestSleep( + [in] long seconds + ); + + typedef enum { + ECHO_ENUM1 = 1, + ECHO_ENUM2 = 2 + } echo_Enum1; + + typedef [v1_enum] enum { + ECHO_ENUM1_32 = 1, + ECHO_ENUM2_32 = 2 + } echo_Enum1_32; + + typedef struct { + echo_Enum1 e1; + echo_Enum1_32 e2; + } echo_Enum2; + + typedef union { + [case(ECHO_ENUM1)] echo_Enum1 e1; + [case(ECHO_ENUM2)] echo_Enum2 e2; + } echo_Enum3; + + void echo_TestEnum( + [in,out,ref] echo_Enum1 *foo1, + [in,out,ref] echo_Enum2 *foo2, + [in,out,ref,switch_is(*foo1)] echo_Enum3 *foo3 + ); + + typedef struct { + long x; + [size_is(x)] short surrounding[*]; + } echo_Surrounding; + + void echo_TestSurrounding( + [in,out,ref] echo_Surrounding *data + ); + + short echo_TestDoublePointer([in] short ***data); +} diff --git a/testprogs/win32/rpcecho/server.c b/testprogs/win32/rpcecho/server.c new file mode 100644 index 0000000000..b092852c15 --- /dev/null +++ b/testprogs/win32/rpcecho/server.c @@ -0,0 +1,208 @@ +/* + RPC echo server. + + Copyright (C) Tim Potter 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#define _WIN32_WINNT 0x0500 + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "rpcecho.h" + +#define RPC_MIN_CALLS 1 +#define RPC_MAX_CALLS 20 +#define RPC_ENDPOINT "\\pipe\\rpcecho" + +void AddOne(int in_data, __RPC_FAR int *out_data) +{ + printf("AddOne: got in_data = %d\n", in_data); + *out_data = in_data + 1; +} + +void EchoData(int len, unsigned char __RPC_FAR in_data[], + unsigned char __RPC_FAR out_data[]) +{ + printf("EchoData: got len = %d\n", len); + + memcpy(out_data, in_data, len); +} + +void SinkData(int len, unsigned char __RPC_FAR in_data[ ]) +{ + printf("SinkData: got len = %d\n", len); +} + +void SourceData(int len, unsigned char __RPC_FAR out_data[ ]) +{ + int i; + + printf("SourceData: got len = %d\n", len); + + for (i = 0; i < len; i++) + out_data[i] = i & 0xff; +} + +void TestCall(wchar_t **s1, wchar_t **s2) +{ + if (*s1) { + printf("s1='%S'\n", *s1); + } else { + printf("s1=NULL\n"); + } + *s2 = L"test string"; +} + +long TestCall2(short level, echo_Info **info) +{ + static echo_Info i; + + printf("TestCall2 level %d\n", level); + + *info = &i; + + switch (level) { + case 1: + i.info1.v = 10; + break; + case 2: + i.info2.v = 20; + break; + case 3: + i.info3.v = 30; + break; + case 4: + i.info4.v = 40; + break; + case 5: + i.info5.v1 = 50; + i.info5.v2 = 51; + break; + case 6: + i.info6.v1 = 60; + i.info6.info1.v = 61; + break; + case 7: + i.info7.v1 = 70; + i.info7.info4.v = 71; + break; + default: + return -1; + } + return 0; +} + +#if 0 +void TestSleep(PRPC_ASYNC_STATE pAsync, long seconds) +{ + long ret; + printf("async Sleeping for %d seconds\n", seconds); + Sleep(1000 * seconds); + ret = seconds; + RpcAsyncCompleteCall(pAsync, &ret); +} +#else +long TestSleep(long seconds) +{ + printf("non-async Sleeping for %d seconds\n", seconds); + Sleep(1000 * seconds); + return seconds; +} +#endif + + +void echo_TestEnum(echo_Enum1 *foo1, + echo_Enum2 *foo2, + echo_Enum3 *foo3) +{ + foo2->e1 = ECHO_ENUM2; +} + +void echo_TestSurrounding(echo_Surrounding *data) +{ + printf("Incoming array of size %d\n", data->x); + data->x *= 2; +} + +short echo_TestDoublePointer(short ***data) +{ + if (!*data) { + printf("WARNING: *data == NULL\n"); + return 0; + } + if (!**data) { + printf("WARNING: **data == NULL\n"); + return 0; + } + printf("Incoming double pointer: %d\n", ***data); + return ***data; +} + +void main(int argc, char **argv) +{ + RPC_STATUS status; + RPC_BINDING_VECTOR *pBindingVector; + + if (argc != 1) { + printf("Usage: rpcechosrv\n"); + exit(0); + } + + status = RpcServerUseProtseqEp("ncacn_np", RPC_MAX_CALLS, "\\pipe\\rpcecho", NULL); + if (status) { + printf("Failed to register ncacn_np endpoint\n"); + exit(status); + } + + status = RpcServerUseProtseqEp("ncacn_ip_tcp", RPC_MAX_CALLS, "1234", NULL); + if (status) { + printf("Failed to register ncacn_ip_tcp endpoint\n"); + exit(status); + } + + status = RpcServerInqBindings(&pBindingVector); + if (status) { + printf("Failed RpcServerInqBindings\n"); + exit(status); + } + + status = RpcEpRegister(rpcecho_v1_0_s_ifspec, pBindingVector, NULL, "rpcecho server"); + if (status) { + printf("Failed RpcEpRegister\n"); + exit(status); + } + + status = RpcServerRegisterIf(rpcecho_v1_0_s_ifspec, NULL, NULL); + + if (status) { + printf("Failed to register interface\n"); + exit(status); + } + + status = RpcServerRegisterAuthInfo(NULL, RPC_C_AUTHN_GSS_NEGOTIATE, NULL, NULL); + if (status) { + printf("Failed to setup auth info\n"); + } + + status = RpcServerListen(RPC_MIN_CALLS, RPC_MAX_CALLS, FALSE); + + if (status) { + printf("RpcServerListen returned error %d\n", status); + exit(status); + } +} + diff --git a/testprogs/win32/rpcecho/utils.c b/testprogs/win32/rpcecho/utils.c new file mode 100644 index 0000000000..09a81d1038 --- /dev/null +++ b/testprogs/win32/rpcecho/utils.c @@ -0,0 +1,32 @@ +/* + RPC echo utility functions. + + Copyright (C) Tim Potter 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "rpcecho.h" + +/* MIDL allocate and free functions */ + +void __RPC_FAR *__RPC_USER midl_user_allocate(size_t len) +{ + return(malloc(len)); +} + +void __RPC_USER midl_user_free(void __RPC_FAR *ptr) +{ + free(ptr); +} diff --git a/testprogs/win32/testmailslot/GNUmakefile b/testprogs/win32/testmailslot/GNUmakefile new file mode 100644 index 0000000000..c1c421527e --- /dev/null +++ b/testprogs/win32/testmailslot/GNUmakefile @@ -0,0 +1,15 @@ +INCLUDES=-I. +CFLAGS=$(INCLUDES) +CC=i586-mingw32msvc-gcc + +all: testmailslot.exe + +clean: + rm -f *~ *.obj testmailslot.exe + +.SUFFIXES: .obj .exe .c + +testmailslot.exe: testmailslot.c + +.c.exe: + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) diff --git a/testprogs/win32/testmailslot/NMakefile b/testprogs/win32/testmailslot/NMakefile new file mode 100644 index 0000000000..e307654fcb --- /dev/null +++ b/testprogs/win32/testmailslot/NMakefile @@ -0,0 +1,10 @@ +INCLUDES=-I +CFLAGS=$(INCLUDES) -Zi -nologo + +all: testmailslot.exe + +clean: + del *~ *.obj testmailslot.exe + +testmailslot.exe: testmailslot.obj + $(CC) $(CFLAGS) -o testmailslot.exe testmailslot.obj $(LIBS) diff --git a/testprogs/win32/testmailslot/testmailslot.c b/testprogs/win32/testmailslot/testmailslot.c new file mode 100644 index 0000000000..b953636fd3 --- /dev/null +++ b/testprogs/win32/testmailslot/testmailslot.c @@ -0,0 +1,80 @@ +/*
+ * Very simple test application for mailslots
+ * (C) 2005 Jelmer Vernooij <jelmer@samba.org>
+ * Published to the public domain
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+int read_slot(const char *mailslotname)
+{
+ HANDLE h;
+ DWORD nr;
+ char data[30000];
+ DWORD nextsize, nummsg = 0;
+
+ if (strncmp(mailslotname, "\\\\.\\mailslot\\", 13) && strncmp(mailslotname, "\\\\*\\mailslot\\", 13)) {
+ printf("Must specify local mailslot name (starting with \\\\.\\mailslot\\)\n");
+ return 1;
+ }
+
+ h = CreateMailslot(mailslotname, 0, MAILSLOT_WAIT_FOREVER, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ printf("Unable to create mailslot %s: %d\n", mailslotname, GetLastError());
+ return 1;
+ }
+
+ if (!ReadFile(h, data, sizeof(data)-1, &nr, NULL)) {
+ printf("Error reading: %d\n", GetLastError());
+ return 1;
+ }
+
+ data[nr] = '\0';
+
+ printf("%s\n", data);
+
+ CloseHandle(h);
+}
+
+int write_slot(const char *mailslotname)
+{
+ HANDLE h;
+ DWORD nw;
+ char data[30000];
+ h = CreateFile(mailslotname, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ printf("Unable to open file: %d\n", GetLastError());
+ return 1;
+ }
+
+ gets(data);
+
+ if (!WriteFile(h, data, strlen(data), &nw, NULL)) {
+ printf("Error writing file: %d\n", GetLastError());
+ return 1;
+ }
+
+ CloseHandle(h);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 3 ||
+ (strcmp(argv[1], "read") && strcmp(argv[1], "write"))) {
+ printf("Usage: %s read|write mailslot\n", argv[0]);
+ return 1;
+ }
+
+ if (!strcmp(argv[1], "read")) {
+ return read_slot(argv[2]);
+ }
+
+ if (!strcmp(argv[1], "write")) {
+ return write_slot(argv[2]);
+ }
+
+ return 0;
+}
diff --git a/testprogs/win32/wmi/echoprocessor.vbs b/testprogs/win32/wmi/echoprocessor.vbs new file mode 100755 index 0000000000..8ce6f7adcd --- /dev/null +++ b/testprogs/win32/wmi/echoprocessor.vbs @@ -0,0 +1,10 @@ +For Each Host In WScript.Arguments
+ Set WMIservice = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & host & "\root\cimv2")
+
+ Set colsettings = WMIservice.ExecQuery("SELECT * FROM Win32_Processor")
+
+
+ For Each proc In colsettings
+ Wscript.Echo(host & ": " & proc.description)
+ Next
+Next
|