diff options
Diffstat (limited to 'testprogs/ejs')
-rwxr-xr-x | testprogs/ejs/base.js | 23 | ||||
-rw-r--r-- | testprogs/ejs/bugs.js | 155 | ||||
-rwxr-xr-x | testprogs/ejs/ldb.js | 385 | ||||
-rwxr-xr-x | testprogs/ejs/minschema.js | 804 | ||||
-rw-r--r-- | testprogs/ejs/minschema_classes.txt | 41 | ||||
-rw-r--r-- | testprogs/ejs/samba3sam.js | 1255 | ||||
-rwxr-xr-x | testprogs/ejs/sprintf.js | 31 |
7 files changed, 2694 insertions, 0 deletions
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"); |