r20457: Print more information before asserting
[samba.git] / testprogs / ejs / samba3sam.js
1 #!/usr/bin/env smbscript
2 /*
3   (C) Jelmer Vernooij <jelmer@samba.org> 2005
4   (C) Martin Kuehl <mkhl@samba.org> 2006
5   Published under the GNU GPL
6   Sponsored by Google Summer of Code
7  */
8
9 var sys;
10 var options = GetOptions(ARGV, "POPT_AUTOHELP", "POPT_COMMON_SAMBA");
11 if (options == undefined) {
12         println("Failed to parse options");
13         return -1;
14 }
15
16 libinclude("base.js");
17
18 if (options.ARGV.length != 2) {
19         println("Usage: samba3sam.js <TESTDIR> <DATADIR>");
20         return -1;
21 }
22
23 var prefix = options.ARGV[0];
24 var datadir = options.ARGV[1];
25
26 function setup_data(obj, ldif)
27 {
28         assert(ldif != undefined);
29         ldif = substitute_var(ldif, obj);
30         assert(ldif != undefined);
31         var ok = obj.db.add(ldif);
32         assert(ok);
33 }
34
35 function setup_modules(ldb, s3, s4, ldif)
36 {
37         assert(ldif != undefined);
38         ldif = substitute_var(ldif, s4);
39         assert(ldif != undefined);
40         var ok = ldb.add(ldif);
41         assert(ok);
42
43         var ldif = "
44 dn: @MAP=samba3sam
45 @FROM: " + s4.BASEDN + "
46 @TO: sambaDomainName=TESTS," + s3.BASEDN + "
47
48 dn: @MODULES
49 @LIST: rootdse,paged_results,server_sort,extended_dn,asq,samldb,objectclass,password_hash,operational,objectguid,rdn_name,samba3sam,partition
50
51 dn: @PARTITION
52 partition: " + s4.BASEDN + ":" + s4.url + "
53 partition: " + s3.BASEDN + ":" + s3.url + "
54 replicateEntries: @SUBCLASSES
55 replicateEntries: @ATTRIBUTES
56 replicateEntries: @INDEXLIST
57 ";
58         var ok = ldb.add(ldif);
59         assert(ok);
60 }
61
62 function test_s3sam_search(ldb)
63 {
64         println("Looking up by non-mapped attribute");
65         var msg = ldb.search("(cn=Administrator)");
66         assert(msg.length == 1);
67         assert(msg[0].cn == "Administrator");
68
69         println("Looking up by mapped attribute");
70         var msg = ldb.search("(name=Backup Operators)");
71         assert(msg.length == 1);
72         assert(msg[0].name == "Backup Operators");
73
74         println("Looking up by old name of renamed attribute");
75         var msg = ldb.search("(displayName=Backup Operators)");
76         assert(msg.length == 0);
77
78         println("Looking up mapped entry containing SID");
79         var msg = ldb.search("(cn=Replicator)");
80         assert(msg.length == 1);
81         println(msg[0].dn);
82         assert(msg[0].dn == "cn=Replicator,ou=Groups,dc=vernstok,dc=nl");
83         assert(msg[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552");
84
85         println("Checking mapping of objectClass");
86         var oc = msg[0].objectClass;
87         assert(oc != undefined);
88         for (var i in oc) {
89                 assert(oc[i] == "posixGroup" || oc[i] == "group");
90         }
91
92         println("Looking up by objectClass");
93         var msg = ldb.search("(|(objectClass=user)(cn=Administrator))");
94         assert(msg != undefined);
95         assert(msg.length == 2);
96         for (var i = 0; i < msg.length; i++) {
97                 assert((msg[i].dn == "unixName=Administrator,ou=Users,dc=vernstok,dc=nl") ||
98                        (msg[i].dn == "unixName=nobody,ou=Users,dc=vernstok,dc=nl"));
99         }
100 }
101
102 function test_s3sam_modify(ldb, s3)
103 {
104         var msg, ok;
105         println("Adding a record that will be fallbacked");
106         ok = ldb.add("
107 dn: cn=Foo
108 foo: bar
109 blah: Blie
110 cn: Foo
111 showInAdvancedViewOnly: TRUE
112 ");
113         if (!ok) {
114                 println(ldb.errstring());
115                 assert(ok);
116         }
117
118         println("Checking for existence of record (local)");
119         /* TODO: This record must be searched in the local database, which is currently only supported for base searches
120          * msg = ldb.search("(cn=Foo)", new Array('foo','blah','cn','showInAdvancedViewOnly'));
121          * TODO: Actually, this version should work as well but doesn't...
122          * 
123          */
124         var attrs =  new Array('foo','blah','cn','showInAdvancedViewOnly');
125         msg = ldb.search("(cn=Foo)", "cn=Foo", ldb.LDB_SCOPE_BASE, attrs);
126         assert(msg.length == 1);
127         assert(msg[0].showInAdvancedViewOnly == "TRUE");
128         assert(msg[0].foo == "bar");
129         assert(msg[0].blah == "Blie");
130
131         println("Adding record that will be mapped");
132         ok = ldb.add("
133 dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
134 objectClass: user
135 unixName: bin
136 unicodePwd: geheim
137 cn: Niemand
138 ");
139         if (!ok) {
140                 println(ldb.errstring());
141                 assert(ok);
142         }
143         assert(ok);
144
145         println("Checking for existence of record (remote)");
146         msg = ldb.search("(unixName=bin)", new Array('unixName','cn','dn', 'unicodePwd'));
147         assert(msg.length == 1);
148         assert(msg[0].cn == "Niemand"); 
149         assert(msg[0].unicodePwd == "geheim");
150
151         println("Checking for existence of record (local && remote)");
152         msg = ldb.search("(&(unixName=bin)(unicodePwd=geheim))", new Array('unixName','cn','dn', 'unicodePwd'));
153         assert(msg.length == 1);                // TODO: should check with more records
154         assert(msg[0].cn == "Niemand");
155         assert(msg[0].unixName == "bin");
156         assert(msg[0].unicodePwd == "geheim");
157
158         println("Checking for existence of record (local || remote)");
159         msg = ldb.search("(|(unixName=bin)(unicodePwd=geheim))", new Array('unixName','cn','dn', 'unicodePwd'));
160         println("got " + msg.length + " replies");
161         assert(msg.length == 1);                // TODO: should check with more records
162         assert(msg[0].cn == "Niemand");
163         assert(msg[0].unixName == "bin" || msg[0].unicodePwd == "geheim");
164
165         println("Checking for data in destination database");
166         msg = s3.db.search("(cn=Niemand)");
167         assert(msg.length >= 1);
168         assert(msg[0].sambaSID == "S-1-5-21-4231626423-2410014848-2360679739-2001");
169         assert(msg[0].displayName == "Niemand");
170
171         println("Adding attribute...");
172         ok = ldb.modify("
173 dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
174 changetype: modify
175 add: description
176 description: Blah
177 ");
178         if (!ok) {
179                 println(ldb.errstring());
180                 assert(ok);
181         }
182         assert(ok);
183
184         println("Checking whether changes are still there...");
185         msg = ldb.search("(cn=Niemand)");
186         assert(msg.length >= 1);
187         assert(msg[0].cn == "Niemand");
188         assert(msg[0].description == "Blah");
189
190         println("Modifying attribute...");
191         ok = ldb.modify("
192 dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
193 changetype: modify
194 replace: description
195 description: Blie
196 ");
197                 if (!ok) {
198                         println(ldb.errstring());
199                         assert(ok);
200                 }
201         assert(ok);
202
203         println("Checking whether changes are still there...");
204         msg = ldb.search("(cn=Niemand)");
205         assert(msg.length >= 1);
206         assert(msg[0].description == "Blie");
207
208         println("Deleting attribute...");
209         ok = ldb.modify("
210 dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
211 changetype: modify
212 delete: description
213 ");
214         if (!ok) {
215                 println(ldb.errstring());
216                 assert(ok);
217         }
218         assert(ok);
219
220         println("Checking whether changes are no longer there...");
221         msg = ldb.search("(cn=Niemand)");
222         assert(msg.length >= 1);
223         assert(msg[0].description == undefined);
224
225         println("Renaming record...");
226         ok = ldb.rename("cn=Niemand,cn=Users,dc=vernstok,dc=nl", "cn=Niemand2,cn=Users,dc=vernstok,dc=nl");
227         assert(ok);
228
229         println("Checking whether DN has changed...");
230         msg = ldb.search("(cn=Niemand2)");
231         assert(msg.length == 1);
232         assert(msg[0].dn == "cn=Niemand2,cn=Users,dc=vernstok,dc=nl");
233
234         println("Deleting record...");
235         ok = ldb.del("cn=Niemand2,cn=Users,dc=vernstok,dc=nl");
236         if (!ok) {
237                 println(ldb.errstring());
238                 assert(ok);
239         }
240
241         println("Checking whether record is gone...");
242         msg = ldb.search("(cn=Niemand2)");
243         assert(msg.length == 0);
244 }
245
246 function test_map_search(ldb, s3, s4)
247 {
248         println("Running search tests on mapped data");
249         var res;
250         var dn;
251         var attrs;
252
253         /* Add a set of split records */
254         var ldif = "
255 dn: " + s4.dn("cn=X") + "
256 objectClass: user
257 cn: X
258 codePage: x
259 revision: x
260 objectCategory: x
261 nextRid: y
262 lastLogon: x
263 description: x
264 objectSid: S-1-5-21-4231626423-2410014848-2360679739-552
265 primaryGroupID: 1-5-21-4231626423-2410014848-2360679739-512
266
267 dn: " + s4.dn("cn=Y") + "
268 objectClass: top
269 cn: Y
270 codePage: x
271 revision: x
272 objectCategory: y
273 nextRid: y
274 lastLogon: y
275 description: x
276
277 dn: " + s4.dn("cn=Z") + "
278 objectClass: top
279 cn: Z
280 codePage: x
281 revision: y
282 objectCategory: z
283 nextRid: y
284 lastLogon: z
285 description: y
286 ";
287         ldif = substitute_var(ldif, s4);
288         assert(ldif != undefined);
289         var ok = ldb.add(ldif);
290         if (!ok) {
291                 println(ldb.errstring());
292                 assert(ok);
293         }
294
295         /* Add a set of remote records */
296         var ldif = "
297 dn: " + s3.dn("cn=A") + "
298 objectClass: posixAccount
299 cn: A
300 sambaNextRid: x
301 sambaBadPasswordCount: x
302 sambaLogonTime: x
303 description: x
304 sambaSID: S-1-5-21-4231626423-2410014848-2360679739-552
305 sambaPrimaryGroupSID: S-1-5-21-4231626423-2410014848-2360679739-512
306
307 dn: " + s3.dn("cn=B") + "
308 objectClass: top
309 cn:B
310 sambaNextRid: x
311 sambaBadPasswordCount: x
312 sambaLogonTime: y
313 description: x
314
315 dn: " + s3.dn("cn=C") + "
316 objectClass: top
317 cn: C
318 sambaNextRid: x
319 sambaBadPasswordCount: y
320 sambaLogonTime: z
321 description: y
322 ";
323         ldif = substitute_var(ldif, s3);
324         assert(ldif != undefined);
325         var ok = s3.db.add(ldif);
326         assert(ok);
327
328         println("Testing search by DN");
329
330         /* Search remote record by local DN */
331         dn = s4.dn("cn=A");
332         attrs = new Array("objectCategory", "lastLogon");
333         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
334         assert(res != undefined);
335         assert(res.length == 1);
336         assert(res[0].dn == dn);
337         assert(res[0].objectCategory == undefined);
338         assert(res[0].lastLogon == "x");
339
340         /* Search remote record by remote DN */
341         dn = s3.dn("cn=A");
342         attrs = new Array("objectCategory", "lastLogon", "sambaLogonTime");
343         res = s3.db.search("", dn, ldb.SCOPE_BASE, attrs);
344         assert(res != undefined);
345         assert(res.length == 1);
346         assert(res[0].dn == dn);
347         assert(res[0].objectCategory == undefined);
348         assert(res[0].lastLogon == undefined);
349         assert(res[0].sambaLogonTime == "x");
350
351         /* Search split record by local DN */
352         dn = s4.dn("cn=X");
353         attrs = new Array("objectCategory", "lastLogon");
354         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
355         assert(res != undefined);
356         assert(res.length == 1);
357         assert(res[0].dn == dn);
358         assert(res[0].objectCategory == "x");
359         assert(res[0].lastLogon == "x");
360
361         /* Search split record by remote DN */
362         dn = s3.dn("cn=X");
363         attrs = new Array("objectCategory", "lastLogon", "sambaLogonTime");
364         res = s3.db.search("", dn, ldb.SCOPE_BASE, attrs);
365         assert(res != undefined);
366         assert(res.length == 1);
367         assert(res[0].dn == dn);
368         assert(res[0].objectCategory == undefined);
369         assert(res[0].lastLogon == undefined);
370         assert(res[0].sambaLogonTime == "x");
371
372         println("Testing search by attribute");
373
374         /* Search by ignored attribute */
375         attrs = new Array("objectCategory", "lastLogon");
376         res = ldb.search("(revision=x)", NULL, ldb. SCOPE_DEFAULT, attrs);
377         assert(res != undefined);
378         assert(res.length == 2);
379         assert(res[0].dn == s4.dn("cn=Y"));
380         assert(res[0].objectCategory == "y");
381         assert(res[0].lastLogon == "y");
382         assert(res[1].dn == s4.dn("cn=X"));
383         assert(res[1].objectCategory == "x");
384         assert(res[1].lastLogon == "x");
385
386         /* Search by kept attribute */
387         attrs = new Array("objectCategory", "lastLogon");
388         res = ldb.search("(description=y)", NULL, ldb. SCOPE_DEFAULT, attrs);
389         assert(res != undefined);
390         assert(res.length == 2);
391         assert(res[0].dn == s4.dn("cn=Z"));
392         assert(res[0].objectCategory == "z");
393         assert(res[0].lastLogon == "z");
394         assert(res[1].dn == s4.dn("cn=C"));
395         assert(res[1].objectCategory == undefined);
396         assert(res[1].lastLogon == "z");
397
398         /* Search by renamed attribute */
399         attrs = new Array("objectCategory", "lastLogon");
400         res = ldb.search("(badPwdCount=x)", NULL, ldb. SCOPE_DEFAULT, attrs);
401         assert(res != undefined);
402         assert(res.length == 2);
403         assert(res[0].dn == s4.dn("cn=B"));
404         assert(res[0].objectCategory == undefined);
405         assert(res[0].lastLogon == "y");
406         assert(res[1].dn == s4.dn("cn=A"));
407         assert(res[1].objectCategory == undefined);
408         assert(res[1].lastLogon == "x");
409
410         /* Search by converted attribute */
411         attrs = new Array("objectCategory", "lastLogon", "objectSid");
412         /* TODO:
413            Using the SID directly in the parse tree leads to conversion
414            errors, letting the search fail with no results.
415         res = ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-552)", NULL, ldb. SCOPE_DEFAULT, attrs);
416         */
417         res = ldb.search("(objectSid=*)", NULL, ldb. SCOPE_DEFAULT, attrs);
418         assert(res != undefined);
419         assert(res.length == 2);
420         assert(res[0].dn == s4.dn("cn=X"));
421         assert(res[0].objectCategory == "x");
422         assert(res[0].lastLogon == "x");
423         assert(res[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552");
424         assert(res[1].dn == s4.dn("cn=A"));
425         assert(res[1].objectCategory == undefined);
426         assert(res[1].lastLogon == "x");
427         assert(res[1].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552");
428
429         /* Search by generated attribute */
430         /* In most cases, this even works when the mapping is missing
431          * a `convert_operator' by enumerating the remote db. */
432         attrs = new Array("objectCategory", "lastLogon", "primaryGroupID");
433         res = ldb.search("(primaryGroupID=512)", NULL, ldb. SCOPE_DEFAULT, attrs);
434         assert(res != undefined);
435         assert(res.length == 1);
436         assert(res[0].dn == s4.dn("cn=A"));
437         assert(res[0].objectCategory == undefined);
438         assert(res[0].lastLogon == "x");
439         assert(res[0].primaryGroupID == "512");
440
441         /* TODO: There should actually be two results, A and X.  The
442          * primaryGroupID of X seems to get corrupted somewhere, and the
443          * objectSid isn't available during the generation of remote (!) data,
444          * which can be observed with the following search.  Also note that Xs
445          * objectSid seems to be fine in the previous search for objectSid... */
446         /*
447         res = ldb.search("(primaryGroupID=*)", NULL, ldb. SCOPE_DEFAULT, attrs);
448         println(res.length + " results found");
449         for (i=0;i<res.length;i++) {
450                 for (obj in res[i]) {
451                         println(obj + ": " + res[i][obj]);
452                 }
453                 println("---");
454         }
455         */
456
457         /* Search by remote name of renamed attribute */
458         attrs = new Array("objectCategory", "lastLogon");
459         res = ldb.search("(sambaBadPasswordCount=*)", "", ldb. SCOPE_DEFAULT, attrs);
460         assert(res != undefined);
461         assert(res.length == 0);
462
463         /* Search by objectClass */
464         attrs = new Array("objectCategory", "lastLogon", "objectClass");
465         res = ldb.search("(objectClass=user)", NULL, ldb. SCOPE_DEFAULT, attrs);
466         assert(res != undefined);
467         assert(res.length == 2);
468         assert(res[0].dn == s4.dn("cn=X"));
469         assert(res[0].objectCategory == "x");
470         assert(res[0].lastLogon == "x");
471         assert(res[0].objectClass != undefined);
472         assert(res[0].objectClass[3] == "user");
473         assert(res[1].dn == s4.dn("cn=A"));
474         assert(res[1].objectCategory == undefined);
475         assert(res[1].lastLogon == "x");
476         assert(res[1].objectClass != undefined);
477         assert(res[1].objectClass[0] == "user");
478
479         /* Prove that the objectClass is actually used for the search */
480         res = ldb.search("(|(objectClass=user)(badPwdCount=x))", NULL, ldb. SCOPE_DEFAULT, attrs);
481         assert(res != undefined);
482         assert(res.length == 3);
483         assert(res[0].dn == s4.dn("cn=B"));
484         assert(res[0].objectCategory == undefined);
485         assert(res[0].lastLogon == "y");
486         assert(res[0].objectClass != undefined);
487         for (i=0;i<res[0].objectClass.length;i++) {
488                 assert(res[0].objectClass[i] != "user");
489         }
490         assert(res[1].dn == s4.dn("cn=X"));
491         assert(res[1].objectCategory == "x");
492         assert(res[1].lastLogon == "x");
493         assert(res[1].objectClass != undefined);
494         assert(res[1].objectClass[3] == "user");
495         assert(res[2].dn == s4.dn("cn=A"));
496         assert(res[2].objectCategory == undefined);
497         assert(res[2].lastLogon == "x");
498         assert(res[2].objectClass != undefined);
499         assert(res[2].objectClass[0] == "user");
500
501         println("Testing search by parse tree");
502
503         /* Search by conjunction of local attributes */
504         attrs = new Array("objectCategory", "lastLogon");
505         res = ldb.search("(&(codePage=x)(revision=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
506         assert(res != undefined);
507         assert(res.length == 2);
508         assert(res[0].dn == s4.dn("cn=Y"));
509         assert(res[0].objectCategory == "y");
510         assert(res[0].lastLogon == "y");
511         assert(res[1].dn == s4.dn("cn=X"));
512         assert(res[1].objectCategory == "x");
513         assert(res[1].lastLogon == "x");
514
515         /* Search by conjunction of remote attributes */
516         attrs = new Array("objectCategory", "lastLogon");
517         res = ldb.search("(&(lastLogon=x)(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
518         assert(res != undefined);
519         assert(res.length == 2);
520         assert(res[0].dn == s4.dn("cn=X"));
521         assert(res[0].objectCategory == "x");
522         assert(res[0].lastLogon == "x");
523         assert(res[1].dn == s4.dn("cn=A"));
524         assert(res[1].objectCategory == undefined);
525         assert(res[1].lastLogon == "x");
526         
527         /* Search by conjunction of local and remote attribute */
528         attrs = new Array("objectCategory", "lastLogon");
529         res = ldb.search("(&(codePage=x)(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
530         assert(res != undefined);
531         assert(res.length == 2);
532         assert(res[0].dn == s4.dn("cn=Y"));
533         assert(res[0].objectCategory == "y");
534         assert(res[0].lastLogon == "y");
535         assert(res[1].dn == s4.dn("cn=X"));
536         assert(res[1].objectCategory == "x");
537         assert(res[1].lastLogon == "x");
538
539         /* Search by conjunction of local and remote attribute w/o match */
540         attrs = new Array("objectCategory", "lastLogon");
541         res = ldb.search("(&(codePage=x)(nextRid=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
542         assert(res != undefined);
543         assert(res.length == 0);
544         res = ldb.search("(&(revision=x)(lastLogon=z))", NULL, ldb.SCOPE_DEFAULT, attrs);
545         assert(res != undefined);
546         assert(res.length == 0);
547
548         /* Search by disjunction of local attributes */
549         attrs = new Array("objectCategory", "lastLogon");
550         res = ldb.search("(|(revision=x)(objectCategory=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
551         assert(res != undefined);
552         assert(res.length == 2);
553         assert(res[0].dn == s4.dn("cn=Y"));
554         assert(res[0].objectCategory == "y");
555         assert(res[0].lastLogon == "y");
556         assert(res[1].dn == s4.dn("cn=X"));
557         assert(res[1].objectCategory == "x");
558         assert(res[1].lastLogon == "x");
559
560         /* Search by disjunction of remote attributes */
561         attrs = new Array("objectCategory", "lastLogon");
562         res = ldb.search("(|(badPwdCount=x)(lastLogon=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
563         assert(res != undefined);
564         assert(res.length == 3);
565         assert(res[0].dn == s4.dn("cn=B"));
566         assert(res[0].objectCategory == undefined);
567         assert(res[0].lastLogon == "y");
568         assert(res[1].dn == s4.dn("cn=X"));
569         assert(res[1].objectCategory == "x");
570         assert(res[1].lastLogon == "x");
571         assert(res[2].dn == s4.dn("cn=A"));
572         assert(res[2].objectCategory == undefined);
573         assert(res[2].lastLogon == "x");
574
575         /* Search by disjunction of local and remote attribute */
576         attrs = new Array("objectCategory", "lastLogon");
577         res = ldb.search("(|(revision=x)(lastLogon=y))", NULL, ldb.SCOPE_DEFAULT, attrs);
578         assert(res != undefined);
579         assert(res.length == 3);
580         assert(res[0].dn == s4.dn("cn=Y"));
581         assert(res[0].objectCategory == "y");
582         assert(res[0].lastLogon == "y");
583         assert(res[1].dn == s4.dn("cn=B"));
584         assert(res[1].objectCategory == undefined);
585         assert(res[1].lastLogon == "y");
586         assert(res[2].dn == s4.dn("cn=X"));
587         assert(res[2].objectCategory == "x");
588         assert(res[2].lastLogon == "x");
589
590         /* Search by disjunction of local and remote attribute w/o match */
591         attrs = new Array("objectCategory", "lastLogon");
592         res = ldb.search("(|(codePage=y)(nextRid=z))", NULL, ldb.SCOPE_DEFAULT, attrs);
593         assert(res != undefined);
594         assert(res.length == 0);
595
596         /* Search by negated local attribute */
597         attrs = new Array("objectCategory", "lastLogon");
598         res = ldb.search("(!(revision=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
599         assert(res != undefined);
600         assert(res.length == 4);
601         assert(res[0].dn == s4.dn("cn=B"));
602         assert(res[0].objectCategory == undefined);
603         assert(res[0].lastLogon == "y");
604         assert(res[1].dn == s4.dn("cn=A"));
605         assert(res[1].objectCategory == undefined);
606         assert(res[1].lastLogon == "x");
607         assert(res[2].dn == s4.dn("cn=Z"));
608         assert(res[2].objectCategory == "z");
609         assert(res[2].lastLogon == "z");
610         assert(res[3].dn == s4.dn("cn=C"));
611         assert(res[3].objectCategory == undefined);
612         assert(res[3].lastLogon == "z");
613
614         /* Search by negated remote attribute */
615         attrs = new Array("objectCategory", "lastLogon");
616         res = ldb.search("(!(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs);
617         assert(res != undefined);
618         assert(res.length == 2);
619         assert(res[0].dn == s4.dn("cn=Z"));
620         assert(res[0].objectCategory == "z");
621         assert(res[0].lastLogon == "z");
622         assert(res[1].dn == s4.dn("cn=C"));
623         assert(res[1].objectCategory == undefined);
624         assert(res[1].lastLogon == "z");
625
626         /* Search by negated conjunction of local attributes */
627         attrs = new Array("objectCategory", "lastLogon");
628         res = ldb.search("(!(&(codePage=x)(revision=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
629         assert(res != undefined);
630         assert(res.length == 4);
631         assert(res[0].dn == s4.dn("cn=B"));
632         assert(res[0].objectCategory == undefined);
633         assert(res[0].lastLogon == "y");
634         assert(res[1].dn == s4.dn("cn=A"));
635         assert(res[1].objectCategory == undefined);
636         assert(res[1].lastLogon == "x");
637         assert(res[2].dn == s4.dn("cn=Z"));
638         assert(res[2].objectCategory == "z");
639         assert(res[2].lastLogon == "z");
640         assert(res[3].dn == s4.dn("cn=C"));
641         assert(res[3].objectCategory == undefined);
642         assert(res[3].lastLogon == "z");
643
644         /* Search by negated conjunction of remote attributes */
645         attrs = new Array("objectCategory", "lastLogon");
646         res = ldb.search("(!(&(lastLogon=x)(description=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
647         assert(res != undefined);
648         assert(res.length == 4);
649         assert(res[0].dn == s4.dn("cn=Y"));
650         assert(res[0].objectCategory == "y");
651         assert(res[0].lastLogon == "y");
652         assert(res[1].dn == s4.dn("cn=B"));
653         assert(res[1].objectCategory == undefined);
654         assert(res[1].lastLogon == "y");
655         assert(res[2].dn == s4.dn("cn=Z"));
656         assert(res[2].objectCategory == "z");
657         assert(res[2].lastLogon == "z");
658         assert(res[3].dn == s4.dn("cn=C"));
659         assert(res[3].objectCategory == undefined);
660         assert(res[3].lastLogon == "z");
661
662         /* Search by negated conjunction of local and remote attribute */
663         attrs = new Array("objectCategory", "lastLogon");
664         res = ldb.search("(!(&(codePage=x)(description=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
665         assert(res != undefined);
666         assert(res.length == 4);
667         assert(res[0].dn == s4.dn("cn=B"));
668         assert(res[0].objectCategory == undefined);
669         assert(res[0].lastLogon == "y");
670         assert(res[1].dn == s4.dn("cn=A"));
671         assert(res[1].objectCategory == undefined);
672         assert(res[1].lastLogon == "x");
673         assert(res[2].dn == s4.dn("cn=Z"));
674         assert(res[2].objectCategory == "z");
675         assert(res[2].lastLogon == "z");
676         assert(res[3].dn == s4.dn("cn=C"));
677         assert(res[3].objectCategory == undefined);
678         assert(res[3].lastLogon == "z");
679
680         /* Search by negated disjunction of local attributes */
681         attrs = new Array("objectCategory", "lastLogon");
682         res = ldb.search("(!(|(revision=x)(objectCategory=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
683         assert(res != undefined);
684         assert(res[0].dn == s4.dn("cn=B"));
685         assert(res[0].objectCategory == undefined);
686         assert(res[0].lastLogon == "y");
687         assert(res[1].dn == s4.dn("cn=A"));
688         assert(res[1].objectCategory == undefined);
689         assert(res[1].lastLogon == "x");
690         assert(res[2].dn == s4.dn("cn=Z"));
691         assert(res[2].objectCategory == "z");
692         assert(res[2].lastLogon == "z");
693         assert(res[3].dn == s4.dn("cn=C"));
694         assert(res[3].objectCategory == undefined);
695         assert(res[3].lastLogon == "z");
696
697         /* Search by negated disjunction of remote attributes */
698         attrs = new Array("objectCategory", "lastLogon");
699         res = ldb.search("(!(|(badPwdCount=x)(lastLogon=x)))", NULL, ldb.SCOPE_DEFAULT, attrs);
700         assert(res != undefined);
701         assert(res.length == 3);
702         assert(res[0].dn == s4.dn("cn=Y"));
703         assert(res[0].objectCategory == "y");
704         assert(res[0].lastLogon == "y");
705         assert(res[1].dn == s4.dn("cn=Z"));
706         assert(res[1].objectCategory == "z");
707         assert(res[1].lastLogon == "z");
708         assert(res[2].dn == s4.dn("cn=C"));
709         assert(res[2].objectCategory == undefined);
710         assert(res[2].lastLogon == "z");
711
712         /* Search by negated disjunction of local and remote attribute */
713         attrs = new Array("objectCategory", "lastLogon");
714         res = ldb.search("(!(|(revision=x)(lastLogon=y)))", NULL, ldb.SCOPE_DEFAULT, attrs);
715         assert(res != undefined);
716         assert(res.length == 3);
717         assert(res[0].dn == s4.dn("cn=A"));
718         assert(res[0].objectCategory == undefined);
719         assert(res[0].lastLogon == "x");
720         assert(res[1].dn == s4.dn("cn=Z"));
721         assert(res[1].objectCategory == "z");
722         assert(res[1].lastLogon == "z");
723         assert(res[2].dn == s4.dn("cn=C"));
724         assert(res[2].objectCategory == undefined);
725         assert(res[2].lastLogon == "z");
726
727         /* Search by complex parse tree */
728         attrs = new Array("objectCategory", "lastLogon");
729         res = ldb.search("(|(&(revision=x)(objectCategory=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", NULL, ldb.SCOPE_DEFAULT, attrs);
730         assert(res != undefined);
731         assert(res.length == 5);
732         assert(res[0].dn == s4.dn("cn=B"));
733         assert(res[0].objectCategory == undefined);
734         assert(res[0].lastLogon == "y");
735         assert(res[1].dn == s4.dn("cn=X"));
736         assert(res[1].objectCategory == "x");
737         assert(res[1].lastLogon == "x");
738         assert(res[2].dn == s4.dn("cn=A"));
739         assert(res[2].objectCategory == undefined);
740         assert(res[2].lastLogon == "x");
741         assert(res[3].dn == s4.dn("cn=Z"));
742         assert(res[3].objectCategory == "z");
743         assert(res[3].lastLogon == "z");
744         assert(res[4].dn == s4.dn("cn=C"));
745         assert(res[4].objectCategory == undefined);
746         assert(res[4].lastLogon == "z");
747
748         /* Clean up */
749         var dns = new Array();
750         dns[0] = s4.dn("cn=A");
751         dns[1] = s4.dn("cn=B");
752         dns[2] = s4.dn("cn=C");
753         dns[3] = s4.dn("cn=X");
754         dns[4] = s4.dn("cn=Y");
755         dns[5] = s4.dn("cn=Z");
756         for (i=0;i<dns.length;i++) {
757                 var ok = ldb.del(dns[i]);
758                 assert(ok);
759         }
760 }
761
762 function test_map_modify(ldb, s3, s4)
763 {
764         println("Running modification tests on mapped data");
765
766         var ldif;
767         var attrs;
768         var dn, dn2;
769         var res;
770         var ok;
771
772         println("Testing modification of local records");
773
774         /* Add local record */
775         dn = "cn=test,dc=idealx,dc=org";
776         ldif = "
777 dn: " + dn + "
778 cn: test
779 foo: bar
780 revision: 1
781 description: test
782 ";
783         ok = ldb.add(ldif);
784         assert(ok);
785         /* Check it's there */
786         attrs = new Array("foo", "revision", "description");
787         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
788         assert(res != undefined);
789         assert(res.length == 1);
790         assert(res[0].dn == dn);
791         assert(res[0].foo == "bar");
792         assert(res[0].revision == "1");
793         assert(res[0].description == "test");
794         /* Check it's not in the local db */
795         res = s4.db.search("(cn=test)", NULL, ldb.SCOPE_DEFAULT, attrs);
796         assert(res != undefined);
797         assert(res.length == 0);
798         /* Check it's not in the remote db */
799         res = s3.db.search("(cn=test)", NULL, ldb.SCOPE_DEFAULT, attrs);
800         assert(res != undefined);
801         assert(res.length == 0);
802
803         /* Modify local record */
804         ldif = "
805 dn: " + dn + "
806 replace: foo
807 foo: baz
808 replace: description
809 description: foo
810 ";
811         ok = ldb.modify(ldif);
812         assert(ok);
813         /* Check in local db */
814         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
815         assert(res != undefined);
816         assert(res.length == 1);
817         assert(res[0].dn == dn);
818         assert(res[0].foo == "baz");
819         assert(res[0].revision == "1");
820         assert(res[0].description == "foo");
821
822         /* Rename local record */
823         dn2 = "cn=toast,dc=idealx,dc=org";
824         ok = ldb.rename(dn, dn2);
825         assert(ok);
826         /* Check in local db */
827         res = ldb.search("", dn2, ldb.SCOPE_BASE, attrs);
828         assert(res != undefined);
829         assert(res.length == 1);
830         assert(res[0].dn == dn2);
831         assert(res[0].foo == "baz");
832         assert(res[0].revision == "1");
833         assert(res[0].description == "foo");
834
835         /* Delete local record */
836         ok = ldb.del(dn2);
837         assert(ok);
838         /* Check it's gone */
839         res = ldb.search("", dn2, ldb.SCOPE_BASE);
840         assert(res != undefined);
841         assert(res.length == 0);
842
843         println("Testing modification of remote records");
844
845         /* Add remote record */
846         dn = s4.dn("cn=test");
847         dn2 = s3.dn("cn=test");
848         ldif = "
849 dn: " + dn2 + "
850 cn: test
851 description: foo
852 sambaBadPasswordCount: 3
853 sambaNextRid: 1001
854 ";
855         ok = s3.db.add(ldif);
856         assert(ok);
857         /* Check it's there */
858         attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid");
859         res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs);
860         assert(res != undefined);
861         assert(res.length == 1);
862         assert(res[0].dn == dn2);
863         assert(res[0].description == "foo");
864         assert(res[0].sambaBadPasswordCount == "3");
865         assert(res[0].sambaNextRid == "1001");
866         /* Check in mapped db */
867         attrs = new Array("description", "badPwdCount", "nextRid");
868         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
869         assert(res != undefined);
870         assert(res.length == 1);
871         assert(res[0].dn == dn);
872         assert(res[0].description == "foo");
873         assert(res[0].badPwdCount == "3");
874         assert(res[0].nextRid == "1001");
875         /* Check in local db */
876         res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs);
877         assert(res != undefined);
878         assert(res.length == 0);
879
880         /* Modify remote data of remote record */
881         ldif = "
882 dn: " + dn + "
883 replace: description
884 description: test
885 replace: badPwdCount
886 badPwdCount: 4
887 ";
888         ok = ldb.modify(ldif);
889         /* Check in mapped db */
890         attrs = new Array("description", "badPwdCount", "nextRid");
891         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
892         assert(res != undefined);
893         assert(res.length == 1);
894         assert(res[0].dn == dn);
895         assert(res[0].description == "test");
896         assert(res[0].badPwdCount == "4");
897         assert(res[0].nextRid == "1001");
898         /* Check in remote db */
899         attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid");
900         res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs);
901         assert(res != undefined);
902         assert(res.length == 1);
903         assert(res[0].dn == dn2);
904         assert(res[0].description == "test");
905         assert(res[0].sambaBadPasswordCount == "4");
906         assert(res[0].sambaNextRid == "1001");
907
908         /* Rename remote record */
909         dn2 = s4.dn("cn=toast");
910         ok = ldb.rename(dn, dn2);
911         assert(ok);
912         /* Check in mapped db */
913         dn = dn2;
914         attrs = new Array("description", "badPwdCount", "nextRid");
915         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
916         assert(res != undefined);
917         assert(res.length == 1);
918         assert(res[0].dn == dn);
919         assert(res[0].description == "test");
920         assert(res[0].badPwdCount == "4");
921         assert(res[0].nextRid == "1001");
922         /* Check in remote db */
923         dn2 = s3.dn("cn=toast");
924         attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid");
925         res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs);
926         assert(res != undefined);
927         assert(res.length == 1);
928         assert(res[0].dn == dn2);
929         assert(res[0].description == "test");
930         assert(res[0].sambaBadPasswordCount == "4");
931         assert(res[0].sambaNextRid == "1001");
932
933         /* Delete remote record */
934         ok = ldb.del(dn);
935         assert(ok);
936         /* Check in mapped db */
937         res = ldb.search("", dn, ldb.SCOPE_BASE);
938         assert(res != undefined);
939         assert(res.length == 0);
940         /* Check in remote db */
941         res = s3.db.search("", dn2, ldb.SCOPE_BASE);
942         assert(res != undefined);
943         assert(res.length == 0);
944
945         /* Add remote record (same as before) */
946         dn = s4.dn("cn=test");
947         dn2 = s3.dn("cn=test");
948         ldif = "
949 dn: " + dn2 + "
950 cn: test
951 description: foo
952 sambaBadPasswordCount: 3
953 sambaNextRid: 1001
954 ";
955         ok = s3.db.add(ldif);
956         assert(ok);
957
958         /* Modify local data of remote record */
959         ldif = "
960 dn: " + dn + "
961 add: revision
962 revision: 1
963 replace: description
964 description: test
965 ";
966         ok = ldb.modify(ldif);
967         /* Check in mapped db */
968         attrs = new Array("revision", "description");
969         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
970         assert(res != undefined);
971         assert(res.length == 1);
972         assert(res[0].dn == dn);
973         assert(res[0].description == "test");
974         assert(res[0].revision == "1");
975         /* Check in remote db */
976         res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs);
977         assert(res != undefined);
978         assert(res.length == 1);
979         assert(res[0].dn == dn2);
980         assert(res[0].description == "test");
981         assert(res[0].revision == undefined);
982         /* Check in local db */
983         res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs);
984         assert(res != undefined);
985         assert(res.length == 1);
986         assert(res[0].dn == dn);
987         assert(res[0].description == undefined);
988         assert(res[0].revision == "1");
989
990         /* Delete (newly) split record */
991         ok = ldb.del(dn);
992         assert(ok);
993
994         println("Testing modification of split records");
995
996         /* Add split record */
997         dn = s4.dn("cn=test");
998         dn2 = s3.dn("cn=test");
999         ldif = "
1000 dn: " + dn + "
1001 cn: test
1002 description: foo
1003 badPwdCount: 3
1004 nextRid: 1001
1005 revision: 1
1006 ";
1007         ok = ldb.add(ldif);
1008         assert(ok);
1009         /* Check it's there */
1010         attrs = new Array("description", "badPwdCount", "nextRid", "revision");
1011         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
1012         assert(res != undefined);
1013         assert(res.length == 1);
1014         assert(res[0].dn == dn);
1015         assert(res[0].description == "foo");
1016         assert(res[0].badPwdCount == "3");
1017         assert(res[0].nextRid == "1001");
1018         assert(res[0].revision == "1");
1019         /* Check in local db */
1020         res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs);
1021         assert(res != undefined);
1022         assert(res.length == 1);
1023         assert(res[0].dn == dn);
1024         assert(res[0].description == undefined);
1025         assert(res[0].badPwdCount == undefined);
1026         assert(res[0].nextRid == undefined);
1027         assert(res[0].revision == "1");
1028         /* Check in remote db */
1029         attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision");
1030         res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs);
1031         assert(res != undefined);
1032         assert(res.length == 1);
1033         assert(res[0].dn == dn2);
1034         assert(res[0].description == "foo");
1035         assert(res[0].sambaBadPasswordCount == "3");
1036         assert(res[0].sambaNextRid == "1001");
1037         assert(res[0].revision == undefined);
1038
1039         /* Modify of split record */
1040         ldif = "
1041 dn: " + dn + "
1042 replace: description
1043 description: test
1044 replace: badPwdCount
1045 badPwdCount: 4
1046 replace: revision
1047 revision: 2
1048 ";
1049         ok = ldb.modify(ldif);
1050         assert(ok);
1051         /* Check in mapped db */
1052         attrs = new Array("description", "badPwdCount", "nextRid", "revision");
1053         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
1054         assert(res != undefined);
1055         assert(res.length == 1);
1056         assert(res[0].dn == dn);
1057         assert(res[0].description == "test");
1058         assert(res[0].badPwdCount == "4");
1059         assert(res[0].nextRid == "1001");
1060         assert(res[0].revision == "2");
1061         /* Check in local db */
1062         res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs);
1063         assert(res != undefined);
1064         assert(res.length == 1);
1065         assert(res[0].dn == dn);
1066         assert(res[0].description == undefined);
1067         assert(res[0].badPwdCount == undefined);
1068         assert(res[0].nextRid == undefined);
1069         assert(res[0].revision == "2");
1070         /* Check in remote db */
1071         attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision");
1072         res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs);
1073         assert(res != undefined);
1074         assert(res.length == 1);
1075         assert(res[0].dn == dn2);
1076         assert(res[0].description == "test");
1077         assert(res[0].sambaBadPasswordCount == "4");
1078         assert(res[0].sambaNextRid == "1001");
1079         assert(res[0].revision == undefined);
1080
1081         /* Rename split record */
1082         dn2 = s4.dn("cn=toast");
1083         ok = ldb.rename(dn, dn2);
1084         assert(ok);
1085         /* Check in mapped db */
1086         dn = dn2;
1087         attrs = new Array("description", "badPwdCount", "nextRid", "revision");
1088         res = ldb.search("", dn, ldb.SCOPE_BASE, attrs);
1089         assert(res != undefined);
1090         assert(res.length == 1);
1091         assert(res[0].dn == dn);
1092         assert(res[0].description == "test");
1093         assert(res[0].badPwdCount == "4");
1094         assert(res[0].nextRid == "1001");
1095         assert(res[0].revision == "2");
1096         /* Check in local db */
1097         res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs);
1098         assert(res != undefined);
1099         assert(res.length == 1);
1100         assert(res[0].dn == dn);
1101         assert(res[0].description == undefined);
1102         assert(res[0].badPwdCount == undefined);
1103         assert(res[0].nextRid == undefined);
1104         assert(res[0].revision == "2");
1105         /* Check in remote db */
1106         dn2 = s3.dn("cn=toast");
1107         attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision");
1108         res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs);
1109         assert(res != undefined);
1110         assert(res.length == 1);
1111         assert(res[0].dn == dn2);
1112         assert(res[0].description == "test");
1113         assert(res[0].sambaBadPasswordCount == "4");
1114         assert(res[0].sambaNextRid == "1001");
1115         assert(res[0].revision == undefined);
1116
1117         /* Delete split record */
1118         ok = ldb.del(dn);
1119         assert(ok);
1120         /* Check in mapped db */
1121         res = ldb.search("", dn, ldb.SCOPE_BASE);
1122         assert(res != undefined);
1123         assert(res.length == 0);
1124         /* Check in local db */
1125         res = s4.db.search("", dn, ldb.SCOPE_BASE);
1126         assert(res != undefined);
1127         assert(res.length == 0);
1128         /* Check in remote db */
1129         res = s3.db.search("", dn2, ldb.SCOPE_BASE);
1130         assert(res != undefined);
1131         assert(res.length == 0);
1132 }
1133
1134 function make_dn(rdn)
1135 {
1136         return rdn + ",sambaDomainName=TESTS," + this.BASEDN;
1137 }
1138
1139 function make_s4dn(rdn)
1140 {
1141         return rdn + "," + this.BASEDN;
1142 }
1143
1144 var ldb = ldb_init();
1145
1146 sys = sys_init();
1147 var ldbfile = prefix + "/" + "test.ldb";
1148 var ldburl = "tdb://" + ldbfile;
1149
1150 var samba4 = new Object("samba4 partition info");
1151 samba4.file = prefix + "/" + "samba4.ldb";
1152 samba4.url = "tdb://" + samba4.file;
1153 samba4.BASEDN = "dc=vernstok,dc=nl";
1154 samba4.db = ldb_init();
1155 samba4.dn = make_s4dn;
1156
1157 var samba3 = new Object("samba3 partition info");
1158 samba3.file = prefix + "/" + "samba3.ldb";
1159 samba3.url = "tdb://" + samba3.file;
1160 samba3.BASEDN = "cn=Samba3Sam";
1161 samba3.db = ldb_init();
1162 samba3.dn = make_dn;
1163
1164 sys.unlink(ldbfile);
1165 sys.unlink(samba3.file);
1166 sys.unlink(samba4.file);
1167
1168 var ok = ldb.connect(ldburl);
1169 assert(ok);
1170 var ok = samba3.db.connect(samba3.url);
1171 assert(ok);
1172 var ok = samba4.db.connect(samba4.url);
1173 assert(ok);
1174
1175 setup_data(samba3, sys.file_load(datadir + "/" + "samba3.ldif"));
1176 setup_modules(ldb, samba3, samba4, sys.file_load(datadir + "/" + "provision_samba3sam.ldif"));
1177
1178 ldb = ldb_init();
1179 var ok = ldb.connect(ldburl);
1180 assert(ok);
1181
1182 test_s3sam_search(ldb);
1183 test_s3sam_modify(ldb, samba3);
1184
1185 sys.unlink(ldbfile);
1186 sys.unlink(samba3.file);
1187 sys.unlink(samba4.file);
1188
1189 ldb = ldb_init();
1190 var ok = ldb.connect(ldburl);
1191 assert(ok);
1192 samba3.db = ldb_init();
1193 var ok = samba3.db.connect(samba3.url);
1194 assert(ok);
1195 samba4.db = ldb_init();
1196 var ok = samba4.db.connect(samba4.url);
1197 assert(ok);
1198
1199 setup_modules(ldb, samba3, samba4, sys.file_load(datadir + "provision_samba3sam.ldif"));
1200
1201 ldb = ldb_init();
1202 var ok = ldb.connect(ldburl);
1203 assert(ok);
1204
1205 test_map_search(ldb, samba3, samba4);
1206 test_map_modify(ldb, samba3, samba4);
1207
1208 sys.unlink(ldbfile);
1209 sys.unlink(samba3.file);
1210 sys.unlink(samba4.file);
1211
1212 return 0;